--[[
Source script taken from: https://github.com/Roblox/creator-docs/blob/main/content/en-us/characters/emotes.md
scriptblox: https://scriptblox.com/script/Universal-Script-7yd7-I-Emote-Script-48024
]]
if _G.EmotesGUIRunning then
getgenv().Notify({
Title = '7yd7 | Emote',
Content = '⚠️ It works It actually works',
Duration = 5
})
return
end
_G.EmotesGUIRunning = true
local HttpService = game:GetService("HttpService")
local RunService = game:GetService("RunService")
local UserInputService = game:GetService("UserInputService")
local ContextActionService = game:GetService("ContextActionService")
local Players = game:GetService("Players")
local CoreGui = game:GetService("CoreGui")
local GuiService = game:GetService("GuiService")
local ContentProvider = game:GetService("ContentProvider")
local StarterGui = game:GetService("StarterGui")
local request = http_request or (syn and syn.request) or request
local State = {
currentMode = "emote",
emotesWalkEnabled = false,
favoriteEnabled = false,
hudEditorActive = false,
speedEmoteEnabled = false,
isLoading = false,
favoriteSetVersion = 0,
favoriteSetBuiltVersion = -1,
emoteCacheVersion = 0,
animationCacheVersion = 0,
isGUICreated = false,
isMonitoringClicks = false,
lastRadialActionTime = 0,
lastWheelVisibleTime = 0,
lastActionTick = 0,
lastRandomEmoteId = nil,
lastRandomAnimationId = nil,
lastRandomVisualSpam = 0,
randomSpamConn = nil,
animImageSpamConn = nil,
animImageSpamMap = nil,
animImageSpamTicks = nil,
animImageSpamToken = 0,
animImageRetry = 0,
randomSlotBlockerConn = nil,
totalEmotesLoaded = 0,
currentPage = 1,
totalPages = 1,
itemsPerPage = 8,
emoteSearchTerm = "",
animationSearchTerm = "",
currentEmoteTrack = nil,
currentCharacter = nil,
emoteClickConnections = {},
guiConnections = {},
animationsData = {},
originalAnimationsData = {},
filteredAnimations = {},
favoriteAnimations = {},
favoriteAnimationsFileName = "FavoriteAnimations.json",
emotesData = {},
originalEmotesData = {},
filteredEmotes = {},
scannedEmotes = {},
favoriteEmotes = {},
favoriteFileName = "FavoriteEmotes.json",
speedEmoteConfigFile = "SpeedEmoteConfig.json",
favoriteEmoteSet = {},
favoriteAnimationSet = {},
emotePageCache = { version = nil, normal = {}, favorites = {} },
animationPageCache = { version = nil, normal = {}, favorites = {} },
suppressSearch = false,
emoteMonitorToken = 0,
animationMonitorToken = 0,
imageUpdateToken = 0,
defaultButtonImage = "rbxassetid://71408678974152",
enabledButtonImage = "rbxassetid://106798555684020",
favoriteIconId = "rbxassetid://97307461910825",
notFavoriteIconId = "rbxassetid://124025954365505",
EmoteTheme = nil,
isApplyingTheme = false,
targetImages = {},
AnimationCachePath = "7yd7/AnimationCache.json",
AnimationCache = {},
AnimationListCachePath = "7yd7/AnimationListCache.json",
EmoteListCachePath = "7yd7/EmoteListCache.json",
CustomAnimationPath = "7yd7/CustomAnimations.json",
CustomAnimations = {},
currentCustomAnimationName = "Default",
customAnimationEditorActive = false,
customAnimationEditingKey = nil,
customAnimationEditingName = nil,
EmotePagePath = "7yd7/EmotePages.json",
EmotePages = {},
currentEmotePageName = "Default",
AnimationPagePath = "7yd7/AnimationPages.json",
AnimationPages = {},
currentAnimationPageName = "Default"
}
Config = {
NotifyEnabled = true,
SearchVisible = true,
FavVisible = true,
ModeVisible = true,
FreezeVisible = true,
SpeedVisible = true,
NavVisible = true,
EmoteSpeed = 1,
EmoteSpeedEnabled = false,
SelectedTheme = "Default",
EmotePage = 1,
AnimationPage = 1,
RandomEnabled = true,
RandomMode = "All",
AuthenticFirstPage = false,
HUDPositions = {},
HUDSizes = {},
HUDProperties = {},
CustomFrames = {},
AutoReloadEnabled = false,
LastPlayedAnimationData = nil,
DiscordVisible = true
}
HUD = {
Connections = {},
IsUnlocked = false,
DefaultPositions = {},
DefaultSizes = {},
DefaultTexts = {},
DefaultPlaceholders = {},
Layouts = {},
LayoutsRemoved = {},
SelectionGui = nil,
SelectedElement = nil,
ResizeHandles = {},
ResizeConnections = {},
FriendlyNames = {
["Under.1left"] = "PrevPage",
["Under.9right"] = "NextPage",
["Under.4pages"] = "TotalPages",
["Under.3TextLabel"] = "Divider",
["Under.2Route-number"] = "CurrentPage",
["Top.Search"] = "Search",
["EmoteWalkButton"] = "Freeze",
["Favorite"] = "Favorite",
["SpeedEmote"] = "SpeedEmote",
["SpeedBox"] = "SpeedBox",
["Changepage"] = "ChangePage",
["Reload"] = "AutoReload",
["Top"] = "Top",
["Under"] = "Under"
}
}
local DEFAULT_IDLE_ICON_ID = "rbxassetid://106798555684020"
local DEFAULT_IDLE_ICON_COLOR = Color3.fromRGB(0, 255, 150)
function DeepCopy(original)
if type(original) ~= "table" then return original end
local copy = {}
for k, v in pairs(original) do
if type(v) == "table" then
v = DeepCopy(v)
end
copy[k] = v
end
return copy
end
function ColorToTable(color)
return {color.R, color.G, color.B}
end
function TableToColor(tbl)
if not tbl or type(tbl) ~= "table" or #tbl < 3 then return Color3.new(1,1,1) end
return Color3.new(tbl[1], tbl[2], tbl[3])
end
function loadAnimationCache()
if isfile and isfile(State.AnimationCachePath) then
local success, decoded = pcall(function()
return HttpService:JSONDecode(readfile(State.AnimationCachePath))
end)
if success and type(decoded) == "table" then
State.AnimationCache = decoded
end
end
end
function saveAnimationCache()
if writefile then
pcall(function()
if not isfolder("7yd7") then makefolder("7yd7") end
writefile(State.AnimationCachePath, HttpService:JSONEncode(State.AnimationCache))
end)
end
end
function resolveAnimationMappings(bundledItems)
local mappings = {}
for _, assetIds in pairs(bundledItems) do
for _, assetId in pairs(assetIds) do
local success, objects = pcall(function()
return game:GetObjects("rbxassetid://" .. assetId)
end)
if success and objects then
local function searchTree(parent, parentPath)
for _, child in pairs(parent:GetChildren()) do
if child:IsA("Animation") then
local animationPath = parentPath .. "." .. child.Name
local pathParts = animationPath:split(".")
table.insert(mappings, {
category = pathParts[#pathParts - 1],
name = pathParts[#pathParts],
animationId = child.AnimationId
})
elseif #child:GetChildren() > 0 then
searchTree(child, parentPath .. "." .. child.Name)
end
end
end
for _, obj in pairs(objects) do
searchTree(obj, obj.Name)
obj.Parent = workspace
task.delay(1, function()
if obj then obj:Destroy() end
end)
end
end
end
end
return mappings
end
function buildCustomSetMappings(setName)
if type(setName) == "string" then
setName = setName:gsub("%s*%-.*$", "")
end
local set = State.CustomAnimations and State.CustomAnimations.Sets and State.CustomAnimations.Sets[setName]
if not set then return {} end
local mappings = {}
for cat, anims in pairs(set) do
if cat ~= "__meta" then
for name, id in pairs(anims) do
if tostring(id) ~= "0" then
table.insert(mappings, {category = cat, name = name, animationId = "rbxassetid://" .. id})
end
end
end
end
return mappings
end
loadAnimationCache()
local UI = {
CustomFrames = {},
Under = nil,
_1left = nil,
_9right = nil,
_4pages = nil,
_3TextLabel = nil,
_2Routenumber = nil,
Top = nil,
EmoteWalkButton = nil,
Search = nil,
Favorite = nil,
SpeedEmote = nil,
SpeedBox = nil,
Changepage = nil,
Reload = nil,
Background = nil
}
local HUD = {
Connections = {},
Strokes = {},
ResizeHandles = {},
ResizeConnections = {},
UndoStack = {},
SelectedElement = nil,
Overlay = nil,
IsUnlocked = false,
ForceVisibleConn = nil,
Layouts = {},
LayoutsRemoved = {},
FriendlyNames = {
["Under.1left"] = "Left Arrow",
["Under.9right"] = "Right Arrow",
["Under.4pages"] = "Total Pages",
["Under.3TextLabel"] = "Separator Label",
["Under.2Route-number"] = "Page Number Box",
["Top.Search"] = "Search/ID Box",
},
DefaultPositions = {
Top = UDim2.new(0.127499998, 0, -0.109999999, 0),
Under = UDim2.new(0.129999995, 0, 1, 0),
EmoteWalkButton = UDim2.new(0.889999986, 0, -0.107500002, 0),
Favorite = UDim2.new(0.0189999994, 0, -0.108000003, 0),
SpeedEmote = UDim2.new(0.888999999, 0, 0, 0),
SpeedBox = UDim2.new(0.0189999398, 0, -0.000499992399, 0),
Changepage = UDim2.new(0.019, 0, 1.021, 0),
Reload = UDim2.new(0.888999999, 0, 1.02100003, 0),
["Left Arrow"] = UDim2.new(0, 0, 0.028, 0),
["Right Arrow"] = UDim2.new(0.169, 0, 0.028, 0),
["Total Pages"] = UDim2.new(0.339, 0, 0.094, 0),
["Separator Label"] = UDim2.new(0.498, 0, 0.028, 0),
["Page Number Box"] = UDim2.new(0.837, 0, 0.094, 0),
["Search/ID Box"] = UDim2.new(0.01, 0, 0.092, 0),
},
DefaultSizes = {
Top = UDim2.new(0.737500012, 0, 0.0949999914, 0),
Under = UDim2.new(0.737500012, 0, 0.132499993, 0),
EmoteWalkButton = UDim2.new(0.0874999985, 0, 0.0874999985, 0),
Favorite = UDim2.new(0.0874999985, 0, 0.0874999985, 0),
SpeedEmote = UDim2.new(0.0874999985, 0, 0.0874999985, 0),
SpeedBox = UDim2.new(0.0874999985, 0, 0.0874999985, 0),
Changepage = UDim2.new(0.087, 0, 0.087, 0),
Reload = UDim2.new(0.0869999975, 0, 0.0869999975, 0),
["Left Arrow"] = UDim2.new(0.169491529, 0, 0.94339627, 0),
["Right Arrow"] = UDim2.new(0.169491529, 0, 0.94339627, 0),
["Total Pages"] = UDim2.new(0.159322038, 0, 0.811320841, 0),
["Separator Label"] = UDim2.new(0.338983059, 0, 0.94339627, 0),
["Page Number Box"] = UDim2.new(0.159322038, 0, 0.811320841, 0),
["Search/ID Box"] = UDim2.new(0.864406765, 0, 0.81578958, 0),
},
DefaultTexts = {
["Left Arrow"] = "",
["Right Arrow"] = "",
["Total Pages"] = "1",
["Separator Label"] = " ------ ",
["Page Number Box"] = "1",
["Search/ID Box"] = "",
["SpeedBox"] = "1",
},
DefaultPlaceholders = {
["Search/ID Box"] = "Search/ID",
}
}
function getAllHUDObjects()
local elems = {}
if UI.Top then elems["Top"] = UI.Top end
if UI.Under then elems["Under"] = UI.Under end
if UI.EmoteWalkButton then elems["EmoteWalkButton"] = UI.EmoteWalkButton end
if UI.Favorite then elems["Favorite"] = UI.Favorite end
if UI.SpeedEmote then elems["SpeedEmote"] = UI.SpeedEmote end
if UI.SpeedBox then elems["SpeedBox"] = UI.SpeedBox end
if UI.Changepage then elems["Changepage"] = UI.Changepage end
if UI.Reload then elems["Reload"] = UI.Reload end
if UI.CustomFrames then
for n, f in pairs(UI.CustomFrames) do
elems[n] = f
end
end
if UI.Top then
for _, child in pairs(UI.Top:GetChildren()) do
if child:IsA("GuiObject") and not child:IsA("UIListLayout") and not child:IsA("UICorner") then
local internalName = "Top." .. child.Name
elems[HUD.FriendlyNames[internalName] or internalName] = child
end
end
end
if UI.Under then
for _, child in pairs(UI.Under:GetChildren()) do
if child:IsA("GuiObject") and not child:IsA("UIListLayout") and not child:IsA("UICorner") then
local internalName = "Under." .. child.Name
elems[HUD.FriendlyNames[internalName] or internalName] = child
end
end
end
return elems
end
function getMovableElements()
local all = getAllHUDObjects()
local movable = {}
for name, el in pairs(all) do
local isChild = false
for _, friendly in pairs(HUD.FriendlyNames) do
if name == friendly then isChild = true; break end
end
if not isChild or HUD.IsUnlocked then
movable[name] = el
end
end
return movable
end
function ColorToTable(c) return {math.round(c.R*255), math.round(c.G*255), math.round(c.B*255)} end
function TableToColor(t)
if type(t) ~= "table" then
return Color3.fromRGB(255, 255, 255)
end
local r = tonumber(t[1]) or 255
local g = tonumber(t[2]) or 255
local b = tonumber(t[3]) or 255
return Color3.fromRGB(r, g, b)
end
local function isThemeDefaultRGB(r, g, b)
return r == 28 and g == 30 and b == 32
end
local AnimationSystem = {
Cache = {},
currentThemeName = "Default"
}
AnimationSystem.LooksLikeGif = function(url)
if not url then return false end
url = string.lower(tostring(url))
return url:find(".gif") or url:find("gif") or url:find("format=gif") or url:find("image/gif")
end
AnimationSystem.NormalizeUrl = function(url)
if not url or url == "" then return url end
local targetUrl = tostring(url)
targetUrl = targetUrl:gsub("%?raw=true", "")
if targetUrl:find("github.com") then
targetUrl = targetUrl:gsub("github.com", "raw.githubusercontent.com")
targetUrl = targetUrl:gsub("/blob/", "/")
targetUrl = targetUrl:gsub("/raw/", "/")
end
if targetUrl:find(" ") and not targetUrl:find("%%20") then
targetUrl = targetUrl:gsub(" ", "%%20")
end
if not targetUrl:find("://") then
local id = targetUrl:match("id=(%d+)") or targetUrl:match("^(%d+)$")
if id then return "rbxassetid://" .. id end
end
return targetUrl
end
AnimationSystem.ParseGifInfo = function(bytes)
if not bytes or #bytes < 13 then return nil end
if bytes:sub(1, 3) ~= "GIF" then return nil end
local function u16le(pos)
local b1 = bytes:byte(pos) or 0
local b2 = bytes:byte(pos + 1) or 0
return b1 + b2 * 256
end
local width = u16le(7)
local height = u16le(9)
local packed = bytes:byte(11) or 0
local gctFlag = bit32.band(packed, 0x80) ~= 0
local gctSize = bit32.band(packed, 0x07)
local offset = 13
if gctFlag then
offset = offset + (3 * (2 ^ (gctSize + 1)))
end
local frames = 0
local delays = {}
local pendingDelay = nil
local function skipSubBlocks(pos)
while pos <= #bytes do
local size = bytes:byte(pos) or 0
pos = pos + 1
if size == 0 then break end
pos = pos + size
end
return pos
end
while offset <= #bytes do
local b = bytes:byte(offset)
if not b then break end
if b == 0x3B then
break
elseif b == 0x21 then
local label = bytes:byte(offset + 1) or 0
if label == 0xF9 then
local delay = u16le(offset + 4)
pendingDelay = delay
offset = offset + 8
else
offset = skipSubBlocks(offset + 2)
end
elseif b == 0x2C then
frames = frames + 1
if pendingDelay then
table.insert(delays, pendingDelay)
pendingDelay = nil
end
local packedImg = bytes:byte(offset + 9) or 0
local lctFlag = bit32.band(packedImg, 0x80) ~= 0
local lctSize = bit32.band(packedImg, 0x07)
offset = offset + 10
if lctFlag then
offset = offset + (3 * (2 ^ (lctSize + 1)))
end
offset = offset + 1
offset = skipSubBlocks(offset)
else
offset = offset + 1
end
end
local totalDelay = 0
for _, d in ipairs(delays) do totalDelay = totalDelay + d end
local avgDelay = (#delays > 0) and (totalDelay / #delays) or 10
return {
width = width,
height = height,
frames = frames > 0 and frames or #delays,
totalDelayCs = totalDelay,
avgDelayCs = avgDelay
}
end
AnimationSystem.ParsePngInfo = function(bytes)
if not bytes or #bytes < 24 then return nil end
if bytes:sub(1, 8) ~= "\137PNG\r\n\26\n" then return nil end
local function u32be(pos)
local b1 = bytes:byte(pos) or 0
local b2 = bytes:byte(pos + 1) or 0
local b3 = bytes:byte(pos + 2) or 0
local b4 = bytes:byte(pos + 3) or 0
return ((b1 * 256 + b2) * 256 + b3) * 256 + b4
end
local width = u32be(17)
local height = u32be(21)
if width <= 0 or height <= 0 then return nil end
return { width = width, height = height }
end
AnimationSystem.StopGif = function()
if State.currentWheelAnimToken then
State.currentWheelAnimToken = State.currentWheelAnimToken + 1
end
end
AnimationSystem.SetImageMode = function(img, custom)
if not img then return end
if custom then
img.ScaleType = Enum.ScaleType.Stretch
img.SliceCenter = Rect.new(0, 0, 0, 0)
img.SliceScale = 1
else
img.ScaleType = Enum.ScaleType.Fit
end
end
AnimationSystem.StartGif = function(img, data)
AnimationSystem.StopGif()
if not img or not data or not data.sprite then return end
State.currentWheelAnimToken = (State.currentWheelAnimToken or 0) + 1
local token = State.currentWheelAnimToken
local frames = data.frames or 1
local frameW = data.frameW or 0
local frameH = data.frameH or 0
local cols = data.cols or 1
local delay = data.delay or 0.1
img.Image = data.sprite
img.ImageRectSize = Vector2.new(frameW, frameH)
local current = 0
local acc = 0
local connection
connection = RunService.Heartbeat:Connect(function(dt)
if token ~= State.currentWheelAnimToken then
connection:Disconnect()
return
end
acc = acc + dt
if acc < delay then return end
acc = 0
current = (current + 1) % frames
local col = current % cols
local row = math.floor(current / cols)
img.ImageRectOffset = Vector2.new(col * frameW, row * frameH)
end)
end
AnimationSystem.AreMetaEqual = function(a, b)
if not a or not b then return a == b end
return a.GifUrl == b.GifUrl and a.SheetUrl == b.SheetUrl and a.Enabled == b.Enabled
end
AnimationSystem.MakeKey = function(gif, sheet)
return tostring(gif) .. "|" .. tostring(sheet)
end
function ApplyFreezeButtonVisual()
if not UI.EmoteWalkButton then return end
UI.EmoteWalkButton.Image = State.emotesWalkEnabled and State.enabledButtonImage or State.defaultButtonImage
end
AnimationSystem.GetIconColor = function(key)
if themes and themes[AnimationSystem.currentThemeName] then
local theme = themes[AnimationSystem.currentThemeName]
if theme.IconColors and theme.IconColors[key] then
return TableToColor(theme.IconColors[key])
end
return TableToColor(theme.ImageColor or {255, 255, 255})
elseif State.EmoteTheme then
local theme = State.EmoteTheme
if theme.IconColors and theme.IconColors[key] then
return TableToColor(theme.IconColors[key])
end
return theme.ImageColor or Color3.new(1, 1, 1)
end
return Color3.fromRGB(255, 255, 255)
end
AnimationSystem.ResetRandomSlot = function(frontFrame)
if not frontFrame then return end
local slot = frontFrame:FindFirstChild("1")
if slot and slot:IsA("ImageLabel") then
slot.ImageColor3 = Color3.fromRGB(255, 255, 255)
slot.Image = ""
local idValue = slot:FindFirstChild("AnimationID")
if idValue then idValue:Destroy() end
end
end
function SafeLoad(url, name)
local success, content
for i = 1, 3 do
success, content = pcall(function() return game:HttpGet(url) end)
if success and content and content ~= "" then break end
task.wait(0.5)
end
if not success or not content or content == "" then
getgenv().Notify({
Title = '7yd7 | Error',
Content = 'Failed to download ' .. (name or "script") .. ' after 3 attempts.',
Duration = 5
})
return function() end
end
local func, err = loadstring(content)
if not func then
warn("7yd7 | SafeLoad: Failed to parse " .. (name or "script") .. ": " .. tostring(err))
return function() end
end
local ok, res = pcall(func)
if not ok then
warn("7yd7 | SafeLoad: Error executing " .. (name or "script") .. ": " .. tostring(res))
return function() end
end
return res
end
SafeLoad("https://raw.githubusercontent.com/7yd7/Menu-7yd7/refs/heads/Script/GUIS/Off-site/Notify.lua", "Notify System")
function GetAsset(asset)
if not asset or asset == "" then return "" end
local assetStr = tostring(asset)
_G.AssetCache = _G.AssetCache or {}
if _G.AssetCache[assetStr] then return _G.AssetCache[assetStr] end
if not assetStr:find("://") and tonumber(assetStr) then
local id = "rbxassetid://" .. assetStr
_G.AssetCache[assetStr] = id
return id
end
if assetStr:find("rbxassetid://") or assetStr:find("rbxasset://") or assetStr:find("rbxthumb://") then
return assetStr
end
if assetStr:find("http") then
local targetUrl = AnimationSystem.NormalizeUrl(assetStr)
local filename = targetUrl:match("([^/]+)$") or "asset.png"
filename = filename:match("([^%?]+)") or filename
filename = filename:gsub("[%c%*%?%\"%<%>%|]", "_")
if filename:lower():find("%.gif$") then
filename = filename:gsub("%.[gG][iI][fF]$", ".png")
end
if not filename:find("%.") then filename = filename .. ".png" end
local path = "7yd7/Assets/" .. filename
if isfile(path) then
local success, result = pcall(function() return getcustomasset(path) end)
if success and result then
_G.AssetCache[assetStr] = result
return result
end
else
if not isfolder("7yd7/Assets") then
pcall(function()
if not isfolder("7yd7") then makefolder("7yd7") end
makefolder("7yd7/Assets")
end)
end
local success, content = pcall(function() return game:HttpGet(targetUrl) end)
if success and content and content ~= "" then
local low = content:sub(1, 100):lower()
if low:find(" State.totalPages then
State.currentPage = State.totalPages
end
updatePageDisplay()
updateEmotes()
SaveConfig()
end)
local randomModes = { "All", "Favorites" }
local randomDropdown = SettingsLib.AddDropdown(GeneralTab, "Random Source", randomModes, Config.RandomMode or "All", function(v)
Config.RandomMode = v
SaveConfig()
end)
if randomDropdown and randomDropdown.Button then
randomDropdown.Button.Text = (Config.RandomMode or "All") .. " ▼"
end
TogglesUI.RandomEnabled = SettingsLib.AddToggle(GeneralTab, "Random Enabled", "Enable/disable random", Config.RandomEnabled, function(v)
Config.RandomEnabled = v
if not v then
pcall(function()
local frontFrame = game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
local slot1 = frontFrame and frontFrame:FindFirstChild("1")
local slot2 = frontFrame and frontFrame:FindFirstChild("2")
if slot1 and slot1:IsA("ImageLabel") and slot2 and slot2:IsA("ImageLabel") then
local img2 = slot2.Image
if img2 and img2 ~= "" then
slot1.Image = img2
end
end
end)
end
State.totalPages = calculateTotalPages()
if State.currentPage > State.totalPages then
State.currentPage = State.totalPages
end
updatePageDisplay()
updateEmotes()
SaveConfig()
end)
local ButtonsTab = SettingsLib.CreateTab("Buttons", 2)
TogglesUI.SearchVisible = SettingsLib.AddToggle(ButtonsTab, "Search Bar", "Show/Hide the search input", Config.SearchVisible, function(v)
Config.SearchVisible = v
ApplyUIVisibility()
SaveConfig()
end)
TogglesUI.FavVisible = SettingsLib.AddToggle(ButtonsTab, "Favorites Button", "Show/Hide the star button", Config.FavVisible, function(v)
Config.FavVisible = v
ApplyUIVisibility()
SaveConfig()
end)
TogglesUI.ModeVisible = SettingsLib.AddToggle(ButtonsTab, "Mode Switcher", "Show/Hide animation mode button", Config.ModeVisible, function(v)
Config.ModeVisible = v
ApplyUIVisibility()
SaveConfig()
end)
TogglesUI.FreezeVisible = SettingsLib.AddToggle(ButtonsTab, "Freeze Button", "Show/Hide emote freeze button", Config.FreezeVisible, function(v)
Config.FreezeVisible = v
ApplyUIVisibility()
SaveConfig()
end)
TogglesUI.SpeedVisible = SettingsLib.AddToggle(ButtonsTab, "Speed Button", "Show/Hide the speed controller", Config.SpeedVisible, function(v)
Config.SpeedVisible = v
ApplyUIVisibility()
SaveConfig()
end)
TogglesUI.NavVisible = SettingsLib.AddToggle(ButtonsTab, "Page Controls", "Show/Hide navigation buttons", Config.NavVisible, function(v)
Config.NavVisible = v
ApplyUIVisibility()
SaveConfig()
end)
TogglesUI.DiscordVisible = SettingsLib.AddToggle(ButtonsTab, "Discord Button", "Show/Hide the discord link button", Config.DiscordVisible, function(v)
Config.DiscordVisible = v
syncDiscordVisibility()
SaveConfig()
end)
local cachedOverlay = nil
local hudEditorItem = SettingsLib.AddItem(ButtonsTab, "HUD Editor", "Reposition buttons & UI elements")
hudEditorItem.LayoutOrder = -10
local hudEditorBtn = SettingsLib:Create("TextButton", {
Parent = hudEditorItem,
BackgroundColor3 = Color3.fromRGB(0, 255, 150),
Position = UDim2.new(1, -80, 0.5, -12),
Size = UDim2.new(0, 70, 0, 24),
Font = Enum.Font.GothamBold,
Text = "EDIT",
TextColor3 = Color3.fromRGB(24, 25, 28),
TextSize = 11
}, { SettingsLib:Create("UICorner", {CornerRadius = UDim.new(0, 6)}) })
hudEditorBtn.MouseButton1Click:Connect(function()
if enterHUDEditor then enterHUDEditor() end
end)
function getBackgroundOverlay()
if cachedOverlay and cachedOverlay.Parent then return cachedOverlay end
local success, result = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Back.Background
.BackgroundCircleOverlay
end)
if success and result then
cachedOverlay = result
return result
end
return nil
end
function DeepCopy(t)
local copy = {}
for k, v in pairs(t) do
if type(v) == "table" then
copy[k] = DeepCopy(v)
else
copy[k] = v
end
end
return copy
end
local ApplyFavoriteButtonVisual
function updateGUIColors()
local backgroundOverlay = getBackgroundOverlay()
if not backgroundOverlay then
return
end
local theme = State.EmoteTheme
if not theme then return end
local bgColor = theme.Background
local accentColor = theme.Accent
local imgColor = theme.ImageColor
local bgTransparency = backgroundOverlay.BackgroundTransparency
local function getIconColor(key)
if theme.IconColors and theme.IconColors[key] then
return TableToColor(theme.IconColors[key])
end
return imgColor
end
if UI._1left then
UI._1left.ImageColor3 = getIconColor("Left")
UI._1left.ImageTransparency = bgTransparency
UI._1left.BackgroundTransparency = 1
end
if UI._9right then
UI._9right.ImageColor3 = getIconColor("Right")
UI._9right.ImageTransparency = bgTransparency
UI._9right.BackgroundTransparency = 1
end
if UI._4pages then
UI._4pages.TextColor3 = bgColor
UI._4pages.TextTransparency = bgTransparency
end
if UI._3TextLabel then
UI._3TextLabel.TextColor3 = bgColor
UI._3TextLabel.TextTransparency = bgTransparency
end
if UI._2Routenumber then
UI._2Routenumber.TextColor3 = bgColor
UI._2Routenumber.PlaceholderColor3 = bgColor
UI._2Routenumber.TextTransparency = bgTransparency
end
if UI.Under then
UI.Under.BackgroundTransparency = 1
end
if UI.Top then
UI.Top.BackgroundColor3 = bgColor
UI.Top.BackgroundTransparency = bgTransparency
end
if UI.EmoteWalkButton then
UI.EmoteWalkButton.BackgroundColor3 = bgColor
UI.EmoteWalkButton.BackgroundTransparency = bgTransparency
end
if UI.CustomFrames then
for _, frame in pairs(UI.CustomFrames) do
frame.BackgroundColor3 = bgColor
frame.BackgroundTransparency = bgTransparency
end
end
if UI.SpeedEmote then
UI.SpeedEmote.BackgroundColor3 = bgColor
UI.SpeedEmote.BackgroundTransparency = bgTransparency
end
if UI.Changepage then
UI.Changepage.BackgroundColor3 = bgColor
UI.Changepage.BackgroundTransparency = bgTransparency
end
if UI.SpeedBox then
UI.SpeedBox.BackgroundColor3 = bgColor
UI.SpeedBox.BackgroundTransparency = bgTransparency
end
if UI.Favorite then
UI.Favorite.BackgroundColor3 = bgColor
UI.Favorite.BackgroundTransparency = bgTransparency
end
if UI.Reload then
UI.Reload.BackgroundColor3 = bgColor
UI.Reload.BackgroundTransparency = bgTransparency
end
if ApplyFavoriteButtonVisual then
ApplyFavoriteButtonVisual()
end
local function applyHUDProperties()
if not Config.HUDProperties then return end
local allMovable = getAllHUDObjects()
for name, uiExt in pairs(allMovable) do
local props = Config.HUDProperties[name]
if props then
if props.ZIndex ~= nil then pcall(function() uiExt.ZIndex = props.ZIndex end) end
if props.BgTrans ~= nil then pcall(function() uiExt.BackgroundTransparency = props.BgTrans end) end
if props.ImgTrans ~= nil and (uiExt:IsA("ImageLabel") or uiExt:IsA("ImageButton")) then pcall(function() uiExt.ImageTransparency = props.ImgTrans end) end
if props.BgColor and type(props.BgColor) == "table" then
local r, g, b = props.BgColor[1], props.BgColor[2], props.BgColor[3]
if r and g and b and not isThemeDefaultRGB(r, g, b) then
pcall(function() uiExt.BackgroundColor3 = Color3.fromRGB(r, g, b) end)
end
end
if props.ImgColor and type(props.ImgColor) == "table" and (uiExt:IsA("ImageLabel") or uiExt:IsA("ImageButton")) then
local r, g, b = props.ImgColor[1], props.ImgColor[2], props.ImgColor[3]
if r and g and b and not isThemeDefaultRGB(r, g, b) then
pcall(function() uiExt.ImageColor3 = Color3.fromRGB(r, g, b) end)
end
end
if props.TxtColor and type(props.TxtColor) == "table" and (uiExt:IsA("TextLabel") or uiExt:IsA("TextBox")) then
local r, g, b = props.TxtColor[1], props.TxtColor[2], props.TxtColor[3]
if r and g and b and not isThemeDefaultRGB(r, g, b) then
pcall(function() uiExt.TextColor3 = Color3.fromRGB(r, g, b) end)
end
end
if props.Radius and uiExt:FindFirstChildWhichIsA("UICorner") then
local s1, o1 = props.Radius:match("{%s*([%d%.%-]+)%s*,%s*([%d%.%-]+)%s*}")
if s1 then pcall(function() uiExt:FindFirstChildWhichIsA("UICorner").CornerRadius = UDim.new(tonumber(s1), tonumber(o1)) end) end
end
end
end
end
applyHUDProperties()
ApplyUIVisibility()
applySettingsToggleStyle()
end
ApplyFavoriteButtonVisual = function()
if not UI.Favorite then return end
local isOn = State.favoriteEnabled
local image = isOn and State.favoriteIconId or State.notFavoriteIconId
if image and image ~= "" then
UI.Favorite.Image = image
end
local colorKey = isOn and "Favorite" or "NotFavorite"
UI.Favorite.ImageColor3 = AnimationSystem.GetIconColor(colorKey)
end
-- Optimizing performance: Removed RenderStepped loop
-- game:GetService("RunService").RenderStepped:Connect(function()
-- updateGUIColors()
-- end)
local ThemeTab = SettingsLib.CreateTab("Theme", 3)
local DiscordPromo = SettingsLib.AddItem(ThemeTab, "WANT THEMES?", "Join our Discord for themes!")
DiscordPromo.LayoutOrder = -1
local CopyBtn = SettingsLib:Create("TextButton", {
Parent = DiscordPromo,
BackgroundColor3 = Color3.fromRGB(0, 255, 150),
Position = UDim2.new(1, -95, 0.5, -12),
Size = UDim2.new(0, 85, 0, 24),
Font = Enum.Font.GothamBold,
Text = "COPY LINK",
TextColor3 = Color3.fromRGB(24, 25, 28),
TextSize = 11
}, { SettingsLib:Create("UICorner", {CornerRadius = UDim.new(0, 6)}) })
CopyBtn.MouseButton1Click:Connect(function()
setclipboard("https://discord.gg/kRfzv2kV7X")
getgenv().Notify({Title = "Discord", Content = "Link copied to clipboard!", Duration = 3})
end)
local ThemeConfigPath = "7yd7/EmoteThemes.json"
local lastSaveTime = 0
local saveDebounce = 1
local pendingSave = false
function SaveThemesImplementation(themes)
if not isfolder("7yd7") then makefolder("7yd7") end
local toSave = { Themes = {}, Order = {}, Selected = themes.Selected or AnimationSystem.currentThemeName }
toSave.Order = themes.Order or {}
for name, data in pairs(themes) do
if name ~= "Default" and name ~= "Order" and name ~= "Selected" then
toSave.Themes[name] = data
end
end
writefile(ThemeConfigPath, HttpService:JSONEncode(toSave))
end
function SaveThemes(themes)
if pendingSave then
pendingSave = "queued"
return
end
pendingSave = true
task.delay(0.5, function()
SaveThemesImplementation(themes)
local wasQueued = pendingSave == "queued"
pendingSave = false
if wasQueued then
SaveThemes(themes)
end
end)
end
function LoadThemes()
local defaultTheme = {
Background = {28, 30, 32},
Accent = {0, 255, 150},
ImageColor = {255, 255, 255},
IconColors = {
Left = {0, 0, 0},
Right = {0, 0, 0}
},
Icons = {
Left = "93111945058621",
Right = "107938916240738",
Walk = "71408678974152",
Favorite = "97307461910825",
NotFavorite = "124025954365505",
Speed = "116056570415896",
Page = "13285615740",
Reload = "127493377027615"
},
Wheel = {
BackgroundImage = "rbxasset://textures/ui/Emotes/Large/SegmentedCircle.png",
BackgroundImageColor = {255, 255, 255},
SelectionGradient = "rbxasset://textures/ui/Emotes/Large/SelectedGradient.png",
SelectionGradientColor = {255, 255, 255},
SelectionLine = "rbxasset://textures/ui/Emotes/Large/SelectedLine.png",
SelectionLineColor = {255, 255, 255}
}
}
local loaded = { Default = defaultTheme, Order = {"Default"} }
if isfile(ThemeConfigPath) then
local success, decoded = pcall(function() return HttpService:JSONDecode(readfile(ThemeConfigPath)) end)
if success and type(decoded) == "table" then
local themesTable = decoded.Themes or decoded
local orderTable = decoded.Order or {}
for name, data in pairs(themesTable) do
if not data.Icons then data.Icons = DeepCopy(defaultTheme.Icons) end
if not data.Wheel then data.Wheel = DeepCopy(defaultTheme.Wheel) end
loaded[name] = data
if name == "Default" then
if not data.IconColors then data.IconColors = {} end
data.IconColors.Left = {0, 0, 0}
data.IconColors.Right = {0, 0, 0}
end
if not decoded.Order and name ~= "Default" then
table.insert(loaded.Order, name)
end
end
if decoded.Order then
loaded.Order = {"Default"}
for _, name in ipairs(decoded.Order) do
if name ~= "Default" and loaded[name] then
table.insert(loaded.Order, name)
end
end
end
if decoded.Selected and loaded[decoded.Selected] then
loaded.Selected = decoded.Selected
end
return loaded
end
end
return loaded
end
State.pendingCustomAnimSave = false
State.SaveCustomAnimationsImplementation = function(animData)
if not isfolder("7yd7") then makefolder("7yd7") end
local toSave = { Sets = {}, Order = animData.Order or {"Default"}, Selected = animData.Selected or "Default" }
for name, data in pairs(animData.Sets) do
if name ~= "Default" then
toSave.Sets[name] = data
end
end
writefile(State.CustomAnimationPath, HttpService:JSONEncode(toSave))
end
State.SaveCustomAnimations = function(animData)
if State.pendingCustomAnimSave then
State.pendingCustomAnimSave = "queued"
return
end
State.pendingCustomAnimSave = true
task.delay(0.5, function()
State.SaveCustomAnimationsImplementation(animData)
local wasQueued = State.pendingCustomAnimSave == "queued"
State.pendingCustomAnimSave = false
if wasQueued then State.SaveCustomAnimations(animData) end
end)
end
State.LoadCustomAnimations = function()
local defaultAnim = {
idle = { Animation1 = 0, Animation2 = 0 },
walk = { WalkAnim = 0 },
run = { RunAnim = 0 },
jump = { JumpAnim = 0 },
fall = { FallAnim = 0 },
climb = { ClimbAnim = 0 },
swimidle = { SwimIdle = 0 },
swim = { Swim = 0 },
__meta = { IconImage = DEFAULT_IDLE_ICON_ID, IconColor = ColorToTable(DEFAULT_IDLE_ICON_COLOR) }
}
local loaded = { Sets = { Default = defaultAnim }, Order = {"Default"}, Selected = "Default" }
if isfile(State.CustomAnimationPath) then
local success, decoded = pcall(function() return HttpService:JSONDecode(readfile(State.CustomAnimationPath)) end)
if success and type(decoded) == "table" then
local setsTable = decoded.Sets or {}
for name, data in pairs(setsTable) do
loaded.Sets[name] = data
end
if decoded.Order then
loaded.Order = {"Default"}
for _, name in ipairs(decoded.Order) do
if name ~= "Default" and loaded.Sets[name] then
table.insert(loaded.Order, name)
end
end
end
if decoded.Selected and loaded.Sets[decoded.Selected] then
loaded.Selected = decoded.Selected
end
end
end
return loaded
end
State.SaveEmotePages = function(pageData)
if not isfolder("7yd7") then makefolder("7yd7") end
local toSave = {
Sets = {},
Order = pageData.Order or {"Default"},
Selected = pageData.Selected or "Default"
}
for name, data in pairs(pageData.Sets) do
if name ~= "Default" then
toSave.Sets[name] = data
end
end
writefile(State.EmotePagePath, HttpService:JSONEncode(toSave))
if pageData.Sets["Default"] then
writefile(State.favoriteFileName, HttpService:JSONEncode(pageData.Sets["Default"]))
end
end
State.SaveAnimationPages = function(pageData)
if not isfolder("7yd7") then makefolder("7yd7") end
local toSave = {
Sets = {},
Order = pageData.Order or {"Default"},
Selected = pageData.Selected or "Default"
}
for name, data in pairs(pageData.Sets) do
if name ~= "Default" then
toSave.Sets[name] = data
end
end
writefile(State.AnimationPagePath, HttpService:JSONEncode(toSave))
if pageData.Sets["Default"] then
writefile(State.favoriteAnimationsFileName, HttpService:JSONEncode(pageData.Sets["Default"]))
end
end
function SwitchEmotePage(pageName)
if not State.EmotePages.Sets[pageName] then return end
State.currentEmotePageName = pageName
State.EmotePages.Selected = pageName
local pageData = State.EmotePages.Sets[pageName]
State.favoriteEmotes = DeepCopy(pageData) or {}
State.favoriteEmoteSet = {}
for _, fav in pairs(State.favoriteEmotes) do
State.favoriteEmoteSet[tostring(fav.id)] = true
end
State.favoriteSetVersion = State.favoriteSetVersion + 1
State.totalPages = calculateTotalPages()
if State.currentPage > State.totalPages then
State.currentPage = State.totalPages
end
updatePageDisplay()
if State.currentMode == "emote" then
updateEmotes()
end
updateAllFavoriteIcons()
end
function SwitchAnimationPage(pageName)
if not State.AnimationPages.Sets[pageName] then return end
State.currentAnimationPageName = pageName
State.AnimationPages.Selected = pageName
local pageData = State.AnimationPages.Sets[pageName]
State.favoriteAnimations = DeepCopy(pageData) or {}
State.favoriteAnimationSet = {}
for _, fav in pairs(State.favoriteAnimations) do
State.favoriteAnimationSet[tostring(fav.id)] = true
end
State.favoriteSetVersion = State.favoriteSetVersion + 1
State.totalPages = calculateTotalPages()
if State.currentPage > State.totalPages then
State.currentPage = State.totalPages
end
updatePageDisplay()
if State.currentMode == "animation" then
updateAnimations()
end
updateAllFavoriteIcons()
end
State.LoadEmotePages = function()
local defaultFavorites = {}
if isfile(State.favoriteFileName) then
local ok, decoded = pcall(function() return HttpService:JSONDecode(readfile(State.favoriteFileName)) end)
if ok and type(decoded) == "table" then
defaultFavorites = decoded
end
end
local loaded = { Sets = { Default = defaultFavorites }, Order = {"Default"}, Selected = "Default" }
if isfile(State.EmotePagePath) then
local success, decoded = pcall(function() return HttpService:JSONDecode(readfile(State.EmotePagePath)) end)
if success and type(decoded) == "table" then
local setsTable = decoded.Sets or {}
for name, data in pairs(setsTable) do
if name ~= "Default" then
loaded.Sets[name] = data
end
end
if decoded.Order then
loaded.Order = {"Default"}
for _, name in ipairs(decoded.Order) do
if name ~= "Default" and loaded.Sets[name] then
table.insert(loaded.Order, name)
end
end
end
if decoded.Selected and (loaded.Sets[decoded.Selected] or decoded.Selected == "Default") then
loaded.Selected = decoded.Selected
end
end
end
return loaded
end
State.LoadAnimationPages = function()
local defaultFavorites = {}
if isfile(State.favoriteAnimationsFileName) then
local ok, decoded = pcall(function() return HttpService:JSONDecode(readfile(State.favoriteAnimationsFileName)) end)
if ok and type(decoded) == "table" then
defaultFavorites = decoded
end
end
local loaded = { Sets = { Default = defaultFavorites }, Order = {"Default"}, Selected = "Default" }
if isfile(State.AnimationPagePath) then
local success, decoded = pcall(function() return HttpService:JSONDecode(readfile(State.AnimationPagePath)) end)
if success and type(decoded) == "table" then
local setsTable = decoded.Sets or {}
for name, data in pairs(setsTable) do
if name ~= "Default" then
loaded.Sets[name] = data
end
end
if decoded.Order then
loaded.Order = {"Default"}
for _, name in ipairs(decoded.Order) do
if name ~= "Default" and loaded.Sets[name] then
table.insert(loaded.Order, name)
end
end
end
if decoded.Selected and (loaded.Sets[decoded.Selected] or decoded.Selected == "Default") then
loaded.Selected = decoded.Selected
end
end
end
return loaded
end
State.EmotePages = State.LoadEmotePages()
State.currentEmotePageName = State.EmotePages.Selected or "Default"
if not State.EmotePages.Sets[State.currentEmotePageName] then
State.currentEmotePageName = "Default"
end
State.favoriteEmotes = DeepCopy(State.EmotePages.Sets[State.currentEmotePageName]) or {}
State.favoriteEmoteSet = {}
for _, fav in pairs(State.favoriteEmotes) do
State.favoriteEmoteSet[tostring(fav.id)] = true
end
State.AnimationPages = State.LoadAnimationPages()
State.currentAnimationPageName = State.AnimationPages.Selected or "Default"
if not State.AnimationPages.Sets[State.currentAnimationPageName] then
State.currentAnimationPageName = "Default"
end
State.favoriteAnimations = DeepCopy(State.AnimationPages.Sets[State.currentAnimationPageName]) or {}
State.favoriteAnimationSet = {}
for _, fav in pairs(State.favoriteAnimations) do
State.favoriteAnimationSet[tostring(fav.id)] = true
end
State.CustomAnimations = State.LoadCustomAnimations()
State.currentCustomAnimationName = State.CustomAnimations.Selected or "Default"
if not State.CustomAnimations.Sets[State.currentCustomAnimationName] then
State.currentCustomAnimationName = "Default"
end
local themes = LoadThemes()
local currentThemeName = Config.SelectedTheme or themes.Selected or "Default"
if not themes[currentThemeName] then currentThemeName = "Default" end
local themeDropdown
function GetNames()
local n = {}
if themes.Order then
for _, name in ipairs(themes.Order) do
if name ~= "Order" and name ~= "Selected" and themes[name] then
table.insert(n, name)
end
end
end
for name, _ in pairs(themes) do
if name ~= "Order" and name ~= "Selected" and not table.find(n, name) then
table.insert(n, name)
end
end
return n
end
local UIElements = {
Background = {},
Accent = {},
ImageColor = {},
Icons = {},
Wheel = {}
}
function ApplyWheelBackgroundImage(bgImg, wheel)
if not bgImg or not wheel then return end
local bgSrc = wheel.BackgroundImage or ""
local isCustomBg = tostring(bgSrc) ~= DEFAULT_WHEEL_BG
local gifUrl, sheetUrl = nil, nil
if bgSrc and tostring(bgSrc):find("\n") then
local lines = {}
for line in tostring(bgSrc):gmatch("[^\r\n]+") do
line = line:match("^%s*(.-)%s*$")
if line ~= "" then table.insert(lines, line) end
end
gifUrl = lines[1]
sheetUrl = lines[2]
elseif tostring(bgSrc):find("|") then
local parts = {}
for part in tostring(bgSrc):gmatch("[^|]+") do
part = part:match("^%s*(.-)%s*$")
if part ~= "" then table.insert(parts, part) end
end
gifUrl = parts[1]
sheetUrl = parts[2]
elseif AnimationSystem.LooksLikeGif(bgSrc) then
gifUrl = bgSrc
end
local targetUrl = AnimationSystem.NormalizeUrl(bgSrc)
if gifUrl then gifUrl = AnimationSystem.NormalizeUrl(gifUrl) end
if sheetUrl then sheetUrl = AnimationSystem.NormalizeUrl(sheetUrl) end
if gifUrl and sheetUrl and sheetUrl ~= "" then
local cacheKey = AnimationSystem.MakeKey(gifUrl, sheetUrl)
local meta = wheel.Animation
if meta and meta.GifUrl == gifUrl and meta.SheetUrl == sheetUrl then
AnimationSystem.Cache[cacheKey] = meta
else
meta = AnimationSystem.Cache[cacheKey]
end
if meta and meta.Enabled == false then
local sheetAsset = GetAsset(sheetUrl)
AnimationSystem.StopGif()
AnimationSystem.SetImageMode(bgImg, true)
bgImg.Image = sheetAsset or ""
bgImg.ImageRectSize = Vector2.new(0, 0)
bgImg.ImageRectOffset = Vector2.new(0, 0)
return
end
if meta and meta.Enabled == true then
local sheetAsset = GetAsset(sheetUrl)
if sheetAsset and sheetAsset ~= "" and (meta.FrameWidth or 0) > 0 and (meta.FrameHeight or 0) > 0 then
local frames = tonumber(meta.Frames) or 0
local cols = tonumber(meta.Cols) or 0
local rows = tonumber(meta.Rows) or 0
local frameW = tonumber(meta.FrameWidth) or 0
local frameH = tonumber(meta.FrameHeight) or 0
local fps = tonumber(meta.FPS) or 10
local delay = fps > 0 and (1 / fps) or 0.1
local spriteData = {
sprite = sheetAsset,
frames = frames,
frameW = frameW,
frameH = frameH,
cols = cols,
rows = rows,
delay = delay
}
AnimationSystem.SetImageMode(bgImg, true)
AnimationSystem.StartGif(bgImg, spriteData)
return
end
end
local okGif, gifBytes = pcall(function() return game:HttpGet(gifUrl) end)
local gifInfo = okGif and gifBytes and AnimationSystem.ParseGifInfo(gifBytes) or nil
local okSheet, sheetBytes = pcall(function() return game:HttpGet(sheetUrl) end)
local sheetInfo = okSheet and sheetBytes and AnimationSystem.ParsePngInfo(sheetBytes) or nil
local sheetAsset = GetAsset(sheetUrl)
if gifInfo and sheetInfo and sheetAsset and sheetAsset ~= "" then
local frameW = gifInfo.width
local frameH = gifInfo.height
local cols = math.max(1, math.floor(sheetInfo.width / frameW))
local rows = math.max(1, math.floor(sheetInfo.height / frameH))
local frames = gifInfo.frames or (cols * rows)
local fps = (gifInfo.avgDelayCs and gifInfo.avgDelayCs > 0) and (100 / gifInfo.avgDelayCs) or 10
local spriteData = {
sprite = sheetAsset,
frames = frames,
frameW = frameW,
frameH = frameH,
cols = cols,
rows = rows,
gifInfo = gifInfo
}
AnimationSystem.SetImageMode(bgImg, true)
AnimationSystem.StartGif(bgImg, spriteData)
local newMeta = {
Enabled = true,
FrameWidth = frameW,
FrameHeight = frameH,
FPS = math.floor(fps + 0.5),
Frames = frames,
Cols = cols,
Rows = rows,
GifUrl = gifUrl,
SheetUrl = sheetUrl
}
if not AnimationSystem.AreMetaEqual(wheel.Animation, newMeta) then
wheel.Animation = newMeta
AnimationSystem.Cache[cacheKey] = newMeta
if AnimationSystem.currentThemeName and AnimationSystem.currentThemeName ~= "Default" then
SaveThemes(themes)
end
end
return
else
AnimationSystem.StopGif()
AnimationSystem.SetImageMode(bgImg, true)
bgImg.Image = sheetAsset or ""
bgImg.ImageRectSize = Vector2.new(0, 0)
bgImg.ImageRectOffset = Vector2.new(0, 0)
local newMeta = {
Enabled = false,
FrameWidth = 0,
FrameHeight = 0,
FPS = 10,
Frames = 1,
Cols = 0,
Rows = 0,
GifUrl = gifUrl,
SheetUrl = sheetUrl
}
if not AnimationSystem.AreMetaEqual(wheel.Animation, newMeta) then
wheel.Animation = newMeta
AnimationSystem.Cache[cacheKey] = newMeta
if AnimationSystem.currentThemeName and AnimationSystem.currentThemeName ~= "Default" then
SaveThemes(themes)
end
end
return
end
end
AnimationSystem.StopGif()
AnimationSystem.SetImageMode(bgImg, isCustomBg)
bgImg.Image = GetAsset(targetUrl)
bgImg.ImageRectSize = Vector2.new(0, 0)
bgImg.ImageRectOffset = Vector2.new(0, 0)
end
function ApplyTheme(themeData)
if State.isApplyingTheme then return end
if not themeData then
warn("7yd7 | ApplyTheme: themeData is nil. Falling back to Default.")
themeData = themes and themes["Default"] or nil
if not themeData then return end
end
State.isApplyingTheme = true
if themeData.Background then
State.EmoteTheme = {
Background = TableToColor(themeData.Background),
Accent = TableToColor(themeData.Accent or {0, 255, 150}),
ImageColor = TableToColor(themeData.ImageColor or {255, 255, 255}),
Icons = themeData.Icons or {},
IconColors = themeData.IconColors or {},
Wheel = themeData.Wheel or {}
}
local function getIconColor(key)
if State.EmoteTheme.IconColors and State.EmoteTheme.IconColors[key] then
return TableToColor(State.EmoteTheme.IconColors[key])
end
return State.EmoteTheme.ImageColor
end
State.favoriteIconId = GetAsset(State.EmoteTheme.Icons.Favorite)
State.notFavoriteIconId = GetAsset(State.EmoteTheme.Icons.NotFavorite)
updateGUIColors()
if UI._1left then UI._1left.Image = GetAsset(State.EmoteTheme.Icons.Left); UI._1left.ImageColor3 = getIconColor("Left") end
if UI._9right then UI._9right.Image = GetAsset(State.EmoteTheme.Icons.Right); UI._9right.ImageColor3 = getIconColor("Right") end
if UI.EmoteWalkButton then
UI.EmoteWalkButton.ImageColor3 = getIconColor("Walk")
ApplyFreezeButtonVisual()
end
if UI.SpeedEmote then UI.SpeedEmote.Image = GetAsset(State.EmoteTheme.Icons.Speed); UI.SpeedEmote.ImageColor3 = getIconColor("Speed") end
if UI.Changepage then UI.Changepage.Image = GetAsset(State.EmoteTheme.Icons.Page); UI.Changepage.ImageColor3 = getIconColor("Page") end
if UI.Reload then UI.Reload.Image = GetAsset(State.EmoteTheme.Icons.Reload); UI.Reload.ImageColor3 = getIconColor("Reload") end
if UI.Favorite then ApplyFavoriteButtonVisual() end
if UI.Background and UI.Background.Main then UI.Background.Main.SetValue(State.EmoteTheme.Background) end
for key, comp in pairs(UIElements.Icons) do
local iconVal = State.EmoteTheme.Icons[key] or ""
local specificColor = State.EmoteTheme.IconColors and State.EmoteTheme.IconColors[key]
local colorVal
if specificColor then
colorVal = TableToColor(specificColor)
else
colorVal = State.EmoteTheme.ImageColor
end
if comp then comp.SetValue(iconVal, colorVal) end
end
local function applyWheel()
pcall(function()
local root = game:GetService("CoreGui"):FindFirstChild("RobloxGui")
if not root then return end
root = root:FindFirstChild("EmotesMenu")
if not root then return end
root = root.Children.Main.EmotesWheel.Back.Background
local wheel = State.EmoteTheme.Wheel
if not wheel then return end
local function getAsset(id)
return GetAsset(id)
end
local bgImg = root:FindFirstChild("BackgroundImage")
if bgImg then
ApplyWheelBackgroundImage(bgImg, wheel)
bgImg.ImageColor3 = TableToColor(wheel.BackgroundImageColor or {255,255,255})
end
local gradContainer = root:FindFirstChild("BackgroundGradient")
local selectionGrad = gradContainer and gradContainer:FindFirstChild("SelectionGradient")
local grad = selectionGrad and selectionGrad:FindFirstChild("SelectedGradient")
if grad then
grad.Image = getAsset(wheel.SelectionGradient)
grad.ImageColor3 = TableToColor(wheel.SelectionGradientColor or {255,255,255})
end
local selection = root:FindFirstChild("Selection")
local selectionEffect = selection and selection:FindFirstChild("SelectionEffect")
local line = selectionEffect and selectionEffect:FindFirstChild("SelectedLine")
if line then
line.Image = getAsset(wheel.SelectionLine)
line.ImageColor3 = TableToColor(wheel.SelectionLineColor or {255,255,255})
end
end)
end
applyWheel()
for key, comp in pairs(UIElements.Wheel) do
local imgVal = State.EmoteTheme.Wheel[key] or ""
local colorVal = TableToColor(State.EmoteTheme.Wheel[key.."Color"] or {255, 255, 255})
if comp then comp.SetValue(imgVal, colorVal) end
end
end
State.isApplyingTheme = false
for name, data in pairs(themes) do
if data == themeData then
AnimationSystem.currentThemeName = name
break
end
end
end
checkEmotesMenuExists = function()
local coreGui = game:GetService("CoreGui")
local robloxGui = coreGui:FindFirstChild("RobloxGui")
if not robloxGui then
return false
end
local emotesMenu = robloxGui:FindFirstChild("EmotesMenu")
if not emotesMenu then
return false
end
local children = emotesMenu:FindFirstChild("Children")
if not children then
return false
end
local main = children:FindFirstChild("Main")
if not main then
return false
end
local emotesWheel = main:FindFirstChild("EmotesWheel")
if not emotesWheel then
return false
end
return true, emotesWheel
end
task.spawn(function()
local attempts = 0
while attempts < 30 do
local exists, emotesWheel = checkEmotesMenuExists()
if exists and emotesWheel then
ApplyTheme(themes[currentThemeName])
emotesWheel:GetPropertyChangedSignal("Visible"):Connect(function()
if emotesWheel.Visible then
task.wait(0.05)
ApplyTheme(themes[currentThemeName])
end
end)
break
end
attempts = attempts + 1
task.wait(1)
end
end)
themeDropdown = SettingsLib.AddDropdown(ThemeTab, "Select Theme", GetNames(), currentThemeName, function(v)
currentThemeName = v
Config.SelectedTheme = v
SaveConfig()
if themes[v] then
SaveThemes(themes)
task.wait(0.1)
ApplyTheme(themes[v])
end
end)
if themeDropdown and themeDropdown.Button and themeDropdown.Button.Parent and themeDropdown.Button.Parent.Parent then
themeDropdown.Button.Parent.Parent.LayoutOrder = 0
end
local BtnItem = SettingsLib.AddItem(ThemeTab, "Theme Management", "Manage your themes")
BtnItem.LayoutOrder = 1
BtnItem.BackgroundColor3 = Color3.fromRGB(35, 38, 42)
BtnItem.Size = UDim2.new(0.95, 0, 0, 70)
for _, v in pairs(BtnItem:GetChildren()) do if v.Name == "Title" or v.Name == "Desc" then v:Destroy() end end
local ManagementContainer = Instance.new("Frame")
ManagementContainer.Parent = BtnItem
ManagementContainer.BackgroundTransparency = 1
ManagementContainer.Size = UDim2.new(1, 0, 1, 0)
local Layout = Instance.new("UIListLayout")
Layout.FillDirection = Enum.FillDirection.Horizontal
Layout.Padding = UDim.new(0, 15)
Layout.HorizontalAlignment = Enum.HorizontalAlignment.Center
Layout.VerticalAlignment = Enum.VerticalAlignment.Center
Layout.Parent = ManagementContainer
local BtnRow = ManagementContainer
function CreatePopup(title, size)
local panel = Instance.new("Frame")
panel.Size = size or UDim2.fromOffset(280, 140)
panel.Position = UDim2.fromScale(0.5, 0.5)
panel.AnchorPoint = Vector2.new(0.5, 0.5)
panel.BackgroundColor3 = Color3.fromHex("18191c")
panel.ZIndex = 2000
panel.Parent = SettingsLib.UI
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 12)
corner.Parent = panel
local stroke = Instance.new("UIStroke")
stroke.Parent = panel
stroke.Color = (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150)
stroke.Thickness = 1.5
stroke.Transparency = 0.5
local lbl = Instance.new("TextLabel")
lbl.Parent = panel
lbl.Size = UDim2.new(1, 0, 0, 35)
lbl.BackgroundTransparency = 1
lbl.Text = title:upper()
lbl.Font = Enum.Font.GothamBold
lbl.TextSize = 13
lbl.TextColor3 = Color3.new(1,1,1)
local content = Instance.new("Frame")
content.Name = "Content"
content.Parent = panel
content.BackgroundTransparency = 1
content.Position = UDim2.new(0, 0, 0, 35)
content.Size = UDim2.new(1, 0, 1, -35)
return panel, content
end
function CreateInput(parent, placeholder, text, isMulti)
local box = Instance.new("TextBox")
box.Size = isMulti and UDim2.new(0.9, 0, 0, 100) or UDim2.new(0.9, 0, 0, 35)
box.Position = UDim2.new(0.05, 0, 0, 5)
box.BackgroundColor3 = Color3.fromRGB(35, 38, 41)
box.TextColor3 = Color3.new(1,1,1)
box.PlaceholderText = placeholder or ""
box.Text = text or ""
box.Font = Enum.Font.Gotham
box.TextSize = 12
box.MultiLine = isMulti
box.TextWrapped = isMulti
box.Parent = parent
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 8)
corner.Parent = box
return box
end
function CreateButton(parent, text, color, pos, size)
local btn = Instance.new("TextButton")
btn.Size = size or UDim2.new(0.4, 0, 0, 32)
btn.Position = pos
btn.BackgroundColor3 = color
btn.Text = text
btn.Font = Enum.Font.GothamBold
btn.TextColor3 = (color.R + color.G + color.B < 1.5) and Color3.new(1,1,1) or Color3.new(0,0,0)
btn.TextSize = 12
btn.Parent = parent
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 8)
corner.Parent = btn
return btn
end
SettingsLib.AddIconButton(BtnRow, "108445456753346", function()
local popup, content = CreatePopup("Create Theme")
local In = CreateInput(content, "Theme Name...")
local Save = CreateButton(content, "SAVE", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.6, 0))
local Cancel = CreateButton(content, "CANCEL", Color3.fromRGB(50, 50, 50), UDim2.new(0.55, 0, 0.6, 0))
Cancel.TextColor3 = Color3.new(1,1,1)
Save.MouseButton1Click:Connect(function()
if In.Text ~= "" and not themes[In.Text] then
themes[In.Text] = DeepCopy(themes[currentThemeName])
if not themes[In.Text].IconColors then themes[In.Text].IconColors = {} end
table.insert(themes.Order, In.Text)
table.sort(themes.Order, function(a, b)
if a == "Default" then return true end
if b == "Default" then return false end
return a:lower() < b:lower()
end)
SaveThemes(themes)
currentThemeName = In.Text
themeDropdown.Refresh(GetNames())
themeDropdown.Button.Text = currentThemeName .. " ▼"
ApplyTheme(themes[currentThemeName])
popup:Destroy()
end
end)
Cancel.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(BtnRow, "71829270056766", function()
if currentThemeName ~= "Default" then
local idx = table.find(themes.Order, currentThemeName)
if idx then table.remove(themes.Order, idx) end
themes[currentThemeName] = nil
SaveThemes(themes)
currentThemeName = "Default"
themeDropdown.Refresh(GetNames())
themeDropdown.Button.Text = "Default ▼"
ApplyTheme(themes["Default"])
end
end)
SettingsLib.AddIconButton(BtnRow, "117761881427472", function()
if currentThemeName == "Default" then return end
local popup, content = CreatePopup("Rename Theme")
local In = CreateInput(content, "New Name...", currentThemeName)
local Save = CreateButton(content, "RENAME", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.6, 0))
local Cancel = CreateButton(content, "CANCEL", Color3.fromRGB(50, 50, 50), UDim2.new(0.55, 0, 0.6, 0))
Cancel.TextColor3 = Color3.new(1,1,1)
Save.MouseButton1Click:Connect(function()
if In.Text ~= "" and not themes[In.Text] then
local idx = table.find(themes.Order, currentThemeName)
if idx then themes.Order[idx] = In.Text end
themes[In.Text] = themes[currentThemeName]
themes[currentThemeName] = nil
currentThemeName = In.Text
SaveThemes(themes)
themeDropdown.Refresh(GetNames())
themeDropdown.Button.Text = currentThemeName .. " ▼"
popup:Destroy()
end
end)
Cancel.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(BtnRow, "78317476576895", function()
local popup, content = CreatePopup("Import Theme", UDim2.fromOffset(320, 240))
local box = CreateInput(content, "Paste Theme JSON here...", "", true)
box.Size = UDim2.new(0.9, 0, 0, 130)
local imp = CreateButton(content, "IMPORT THEME", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
imp.MouseButton1Click:Connect(function()
local s, d = pcall(function() return HttpService:JSONDecode(box.Text) end)
if s and type(d) == "table" and d.name then
if d.name == "Default" then
getgenv().Notify({Title = "Error", Content = "Cannot overwrite 'Default' theme.", Duration = 3})
return
end
if not themes[d.name] then
table.insert(themes.Order, d.name)
end
themes[d.name] = d.data
SaveThemes(themes)
themeDropdown.Refresh(GetNames())
popup:Destroy()
else
getgenv().Notify({Title = "Error", Content = "Invalid JSON Format!", Duration = 3})
end
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "×"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.Parent = popup
close.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(BtnRow, "107588515524752", function()
local exportData = { name = currentThemeName, data = themes[currentThemeName] }
local json = HttpService:JSONEncode(exportData)
local popup, content = CreatePopup("Export Theme", UDim2.fromOffset(320, 240))
local box = CreateInput(content, "", json, true)
box.Size = UDim2.new(0.9, 0, 0, 130)
box.TextEditable = false
local copy = CreateButton(content, "COPY TO CLIPBOARD", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
copy.MouseButton1Click:Connect(function()
setclipboard(json)
copy.Text = "COPIED!"
task.delay(1, function() copy.Text = "COPY TO CLIPBOARD" end)
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "×"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.Parent = popup
close.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
function SmartUpdate(key, subkey, val)
if currentThemeName == "Default" then
getgenv().Notify({Title = "Theme", Content = "Cannot modify Default theme. Create a new one!", Duration = 2})
return
end
if themes[currentThemeName] then
if not themes[currentThemeName][key] then themes[currentThemeName][key] = {} end
if subkey then
themes[currentThemeName][key][subkey] = val
else
themes[currentThemeName][key] = val
end
SaveThemes(themes)
ApplyTheme(themes[currentThemeName])
end
end
local WheelFolder = SettingsLib.AddFolder(ThemeTab, "Wheel Settings")
WheelFolder.Parent.LayoutOrder = 1.1
function AddWheelInput(title, wheelKey)
local initialData = themes["Default"].Wheel[wheelKey]
local initialColor = TableToColor(themes["Default"].Wheel[wheelKey.."Color"])
local current = (themes[currentThemeName].Wheel and themes[currentThemeName].Wheel[wheelKey]) or initialData
local currentColor = TableToColor((themes[currentThemeName].Wheel and themes[currentThemeName].Wheel[wheelKey.."Color"]) or themes["Default"].Wheel[wheelKey.."Color"])
local comp = SettingsLib.AddAssetColor(WheelFolder, title, "Asset ID...", current, currentColor, function(text, color)
if currentThemeName == "Default" then
getgenv().Notify({Title = "Theme", Content = "Cannot modify Default theme!", Duration = 2})
return
end
if themes[currentThemeName] then
if not themes[currentThemeName].Wheel then themes[currentThemeName].Wheel = {} end
themes[currentThemeName].Wheel[wheelKey] = text
themes[currentThemeName].Wheel[wheelKey.."Color"] = ColorToTable(color)
SaveThemes(themes)
ApplyTheme(themes[currentThemeName])
end
end)
UIElements.Wheel[wheelKey] = comp
local resetBtn = SettingsLib:Create("ImageButton", {
Parent = comp.Item,
BackgroundTransparency = 1,
Position = UDim2.new(1, -120, 0.5, -10),
Size = UDim2.fromOffset(20, 20),
Image = "rbxassetid://127493377027615",
ScaleType = Enum.ScaleType.Fit,
ZIndex = 10
})
resetBtn.MouseButton1Click:Connect(function()
if currentThemeName == "Default" then return end
comp.SetValue(initialData, initialColor)
if themes[currentThemeName] then
if not themes[currentThemeName].Wheel then themes[currentThemeName].Wheel = {} end
themes[currentThemeName].Wheel[wheelKey] = initialData
themes[currentThemeName].Wheel[wheelKey.."Color"] = ColorToTable(initialColor)
SaveThemes(themes)
ApplyTheme(themes[currentThemeName])
end
end)
end
AddWheelInput("Wheel Background", "BackgroundImage")
AddWheelInput("Selection Gradient", "SelectionGradient")
AddWheelInput("Selection Line", "SelectionLine")
local BackgroundFolder = SettingsLib.AddFolder(ThemeTab, "Background Settings")
BackgroundFolder.Parent.LayoutOrder = 2
UIElements.Background.Main = SettingsLib.AddColorPicker(BackgroundFolder, "Main Background", TableToColor(themes[currentThemeName].Background), function(c)
SmartUpdate("Background", nil, ColorToTable(c))
end)
local IconSettingsFolder = SettingsLib.AddFolder(ThemeTab, "Icon Settings")
IconSettingsFolder.Parent.LayoutOrder = 3
function AddAssetInput(title, iconKey)
local current = (themes[currentThemeName].Icons and themes[currentThemeName].Icons[iconKey]) or ""
local defaultText = (themes["Default"].Icons and themes["Default"].Icons[iconKey]) or ""
local currentColor = Color3.new(1,1,1)
if themes[currentThemeName].IconColors and themes[currentThemeName].IconColors[iconKey] then
currentColor = TableToColor(themes[currentThemeName].IconColors[iconKey])
elseif themes[currentThemeName].ImageColor then
currentColor = TableToColor(themes[currentThemeName].ImageColor)
end
local defaultColor = Color3.new(1,1,1)
if themes["Default"].IconColors and themes["Default"].IconColors[iconKey] then
defaultColor = TableToColor(themes["Default"].IconColors[iconKey])
elseif themes["Default"].ImageColor then
defaultColor = TableToColor(themes["Default"].ImageColor)
end
local comp = SettingsLib.AddInputWithColor(IconSettingsFolder, title, "Asset ID...", defaultText, defaultColor, function(text, color)
local s, err = pcall(function()
if currentThemeName == "Default" then
getgenv().Notify({Title = "Theme", Content = "Cannot modify Default theme!", Duration = 2})
return
end
if themes[currentThemeName] then
if not themes[currentThemeName].Icons then themes[currentThemeName].Icons = {} end
if not themes[currentThemeName].IconColors then themes[currentThemeName].IconColors = {} end
local cTable = ColorToTable(color)
themes[currentThemeName].Icons[iconKey] = text
themes[currentThemeName].IconColors[iconKey] = cTable
SaveThemes(themes)
ApplyTheme(themes[currentThemeName])
end
end)
if not s then
warn("Theme Save Error: " .. tostring(err))
getgenv().Notify({Title = "Error", Content = "Failed to save color!", Duration = 3})
end
end)
comp.SetValue(current, currentColor)
UIElements.Icons[iconKey] = comp
end
AddAssetInput("Left Arrow", "Left")
AddAssetInput("Right Arrow", "Right")
AddAssetInput("Walk Icon", "Walk")
AddAssetInput("Speed Icon", "Speed")
AddAssetInput("Page Icon", "Page")
AddAssetInput("Reload Icon", "Reload")
AddAssetInput("Favorite (Star)", "Favorite")
AddAssetInput("Not Favorite", "NotFavorite")
State.exitCustomAnimationEditor = function()
if not State.customAnimationEditorActive then return end
State.customAnimationEditorActive = false
State.customAnimationEditingKey = nil
State.customAnimationEditingName = nil
for _, conn in pairs(State.CustomAnimEditorConnections or {}) do
pcall(function() conn:Disconnect() end)
end
State.CustomAnimEditorConnections = {}
if State.CustomAnimOverlay and State.CustomAnimOverlay.Parent then
State.CustomAnimOverlay:Destroy()
end
State.CustomAnimOverlay = nil
if State.CustomAnimForceVisibleConn then
State.CustomAnimForceVisibleConn:Disconnect()
State.CustomAnimForceVisibleConn = nil
end
if UI.Search then UI.Search.TextEditable = true; UI.Search.Active = true end
if UI.SpeedBox then UI.SpeedBox.TextEditable = true; UI.SpeedBox.Active = true end
if UI._2Routenumber then UI._2Routenumber.TextEditable = true; UI._2Routenumber.Active = true end
pcall(function() game:GetService("GuiService"):SetEmotesMenuOpen(false) end)
pcall(function() game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Visible = false end)
local main = getSettingsMainFrame()
if main then main.Visible = true end
if syncToggleVisibility then syncToggleVisibility() end
if State.RefreshCustomAnimUI then State.RefreshCustomAnimUI() end
if State.currentMode ~= "animation" then
State.currentMode = "animation"
State.suppressSearch = true
if UI.Search then UI.Search.Text = State.animationSearchTerm end
State.suppressSearch = false
State.currentPage = Config.AnimationPage or 1
State.totalPages = calculateTotalPages()
updatePageDisplay()
updateEmotes()
if updateScriptPriorityOverlay then updateScriptPriorityOverlay() end
State.animationMonitorToken = State.animationMonitorToken + 1
local token = State.animationMonitorToken
State.isMonitoringClicks = true
if monitorAnimations then
task.spawn(function() monitorAnimations(token) end)
end
end
end
State.enterCustomAnimationEditor = function(category, animName)
if State.customAnimationEditorActive then return end
if State.currentCustomAnimationName == "Default" then
getgenv().Notify({ Title = "7yd7 | Error", Content = "Cannot edit Default Animation set. Create a new one!", Duration = 3 })
return
end
State.customAnimationEditorActive = true
State.customAnimationEditingKey = category
State.customAnimationEditingName = animName
if State.currentMode ~= "animation" then
State.currentMode = "animation"
State.suppressSearch = true
if UI.Search then UI.Search.Text = State.animationSearchTerm end
State.suppressSearch = false
State.currentPage = Config.AnimationPage or 1
State.totalPages = calculateTotalPages()
updatePageDisplay()
updateEmotes()
if updateScriptPriorityOverlay then updateScriptPriorityOverlay() end
State.animationMonitorToken = State.animationMonitorToken + 1
local token = State.animationMonitorToken
State.isMonitoringClicks = true
if monitorAnimations then
task.spawn(function()
monitorAnimations(token)
end)
end
local beforeVersion = State.animationCacheVersion
task.spawn(function()
if fetchAllAnimations then
fetchAllAnimations()
else
return
end
if State.currentMode ~= "animation" then return end
if State.animationCacheVersion ~= beforeVersion then
State.suppressSearch = true
if UI.Search then UI.Search.Text = State.animationSearchTerm end
State.suppressSearch = false
State.currentPage = Config.AnimationPage or 1
State.totalPages = calculateTotalPages()
updatePageDisplay()
updateEmotes()
if updateScriptPriorityOverlay then updateScriptPriorityOverlay() end
end
end)
end
GuiService:SetEmotesMenuOpen(false)
task.wait(0.15)
local exists, emotesWheel = checkEmotesMenuExists()
if not exists then State.customAnimationEditorActive = false; return end
emotesWheel.Visible = true
State.CustomAnimForceVisibleConn = RunService.Heartbeat:Connect(function()
if not State.customAnimationEditorActive then return end
pcall(function()
local _, ew = checkEmotesMenuExists()
if ew then ew.Visible = true end
end)
end)
local main = getSettingsMainFrame()
if main then main.Visible = false end
if syncToggleVisibility then syncToggleVisibility() end
local overlay = Instance.new("Frame")
overlay.Name = "CustomAnimOverlay"
overlay.Parent = SettingsLib.UI
overlay.BackgroundTransparency = 1
overlay.Size = UDim2.fromScale(1, 1)
overlay.ZIndex = 6000
overlay.Active = false
State.CustomAnimOverlay = overlay
local bc = Instance.new("Frame")
bc.Parent = overlay
bc.BackgroundTransparency = 1
bc.AnchorPoint = Vector2.new(1, 0)
bc.Position = UDim2.new(1, -10, 0, 10)
bc.Size = UDim2.fromOffset(42, 42)
bc.ZIndex = 6000
local backBtn = Instance.new("ImageButton")
backBtn.Name = "CustomAnimBackBtn"
backBtn.Size = UDim2.fromOffset(42, 42)
backBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
backBtn.BackgroundTransparency = 0.4
backBtn.Image = "rbxassetid://79024388644722"
backBtn.ZIndex = 6001
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 10)
corner.Parent = backBtn
backBtn.Parent = bc
State.CustomAnimEditorConnections = State.CustomAnimEditorConnections or {}
table.insert(State.CustomAnimEditorConnections, backBtn.MouseButton1Click:Connect(function()
State.exitCustomAnimationEditor()
end))
if UI._2Routenumber then UI._2Routenumber.TextEditable = false; UI._2Routenumber.Active = false; pcall(function() UI._2Routenumber:ReleaseFocus() end) end
getgenv().Notify({ Title = "7yd7 | Animation Editor", Content = "🖱️ Select an animation from the wheel to set for " .. animName, Duration = 5 })
end
State.CustomAnimTab = SettingsLib.CreateTab("Animation", 4)
State.CustomAnimDropdown = SettingsLib.AddDropdown(State.CustomAnimTab, "Select Animation", State.CustomAnimations.Order, State.currentCustomAnimationName, function(v)
State.currentCustomAnimationName = v
State.CustomAnimations.Selected = v
State.SaveCustomAnimations(State.CustomAnimations)
if State.RefreshCustomAnimUI then State.RefreshCustomAnimUI() end
if State.ApplyCustomAnimIconUI then State.ApplyCustomAnimIconUI() end
if refreshCustomAnimationState then refreshCustomAnimationState(false) end
end)
if State.CustomAnimDropdown and State.CustomAnimDropdown.Button and State.CustomAnimDropdown.Button.Parent and State.CustomAnimDropdown.Button.Parent.Parent then
State.CustomAnimDropdown.Button.Parent.Parent.LayoutOrder = 0
end
local CustomAnimBtnItem = SettingsLib.AddItem(State.CustomAnimTab, "Animation Management", "Manage your animations")
CustomAnimBtnItem.LayoutOrder = 1
CustomAnimBtnItem.BackgroundColor3 = Color3.fromRGB(35, 38, 42)
CustomAnimBtnItem.Size = UDim2.new(0.95, 0, 0, 70)
for _, v in pairs(CustomAnimBtnItem:GetChildren()) do if v.Name == "Title" or v.Name == "Desc" then v:Destroy() end end
local CustomAnimMgtContainer = Instance.new("Frame")
CustomAnimMgtContainer.Parent = CustomAnimBtnItem
CustomAnimMgtContainer.BackgroundTransparency = 1
CustomAnimMgtContainer.Size = UDim2.new(1, 0, 1, 0)
local CustomAnimLayout = Instance.new("UIListLayout")
CustomAnimLayout.FillDirection = Enum.FillDirection.Horizontal
CustomAnimLayout.Padding = UDim.new(0, 15)
CustomAnimLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
CustomAnimLayout.VerticalAlignment = Enum.VerticalAlignment.Center
CustomAnimLayout.Parent = CustomAnimMgtContainer
function NormalizeCustomAnimationData(animData)
local defaultAnim = {
idle = { Animation1 = 0, Animation2 = 0 },
walk = { WalkAnim = 0 },
run = { RunAnim = 0 },
jump = { JumpAnim = 0 },
fall = { FallAnim = 0 },
swimidle = { SwimIdle = 0 },
swim = { Swim = 0 },
__meta = { IconImage = DEFAULT_IDLE_ICON_ID, IconColor = ColorToTable(DEFAULT_IDLE_ICON_COLOR) }
}
local result = { Sets = { Default = DeepCopy(defaultAnim) }, Order = {"Default"}, Selected = "Default" }
if type(animData) ~= "table" then return result end
local setsTable = animData.Sets or animData
if type(setsTable) == "table" then
for name, data in pairs(setsTable) do
if type(data) == "table" then
if name == "Default" then
result.Sets.Default = data
else
result.Sets[name] = data
end
data.__meta = data.__meta or {}
if data.__meta.IconImage == nil then data.__meta.IconImage = DEFAULT_IDLE_ICON_ID end
if data.__meta.IconColor == nil then data.__meta.IconColor = ColorToTable(DEFAULT_IDLE_ICON_COLOR) end
end
end
end
local order = animData.Order
if type(order) == "table" then
for _, name in ipairs(order) do
if name ~= "Default" and result.Sets[name] then
table.insert(result.Order, name)
end
end
else
for name, _ in pairs(result.Sets) do
if name ~= "Default" then table.insert(result.Order, name) end
end
end
local selected = animData.Selected
if type(selected) == "string" and result.Sets[selected] then
result.Selected = selected
end
return result
end
function MakeUniqueSetName(baseSets, desiredName)
if not baseSets[desiredName] then return desiredName end
local i = 2
local candidate = desiredName .. " (Imported)"
if not baseSets[candidate] then return candidate end
while true do
candidate = desiredName .. " (Imported " .. i .. ")"
if not baseSets[candidate] then return candidate end
i = i + 1
end
end
SettingsLib.AddIconButton(CustomAnimMgtContainer, "108445456753346", function()
local popup, content = CreatePopup("Create Animation")
local In = CreateInput(content, "Animation Name...")
local Save = CreateButton(content, "SAVE", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.6, 0))
local Cancel = CreateButton(content, "CANCEL", Color3.fromRGB(50, 50, 50), UDim2.new(0.55, 0, 0.6, 0))
Cancel.TextColor3 = Color3.new(1,1,1)
Save.MouseButton1Click:Connect(function()
if In.Text ~= "" and not State.CustomAnimations.Sets[In.Text] then
local defaultAnim = {
idle = { Animation1 = 0, Animation2 = 0 },
walk = { WalkAnim = 0 },
run = { RunAnim = 0 },
jump = { JumpAnim = 0 },
fall = { FallAnim = 0 },
swimidle = { SwimIdle = 0 },
swim = { Swim = 0 },
__meta = { IconImage = DEFAULT_IDLE_ICON_ID, IconColor = ColorToTable(DEFAULT_IDLE_ICON_COLOR) }
}
State.CustomAnimations.Sets[In.Text] = defaultAnim
table.insert(State.CustomAnimations.Order, In.Text)
table.sort(State.CustomAnimations.Order, function(a, b)
if a == "Default" then return true end
if b == "Default" then return false end
return a:lower() < b:lower()
end)
State.currentCustomAnimationName = In.Text
State.CustomAnimations.Selected = In.Text
State.SaveCustomAnimations(State.CustomAnimations)
if State.CustomAnimDropdown then
State.CustomAnimDropdown.Refresh(State.CustomAnimations.Order)
State.CustomAnimDropdown.Button.Text = State.currentCustomAnimationName .. " ▼"
end
if State.RefreshCustomAnimUI then State.RefreshCustomAnimUI() end
if State.ApplyCustomAnimIconUI then State.ApplyCustomAnimIconUI() end
if refreshCustomAnimationState then refreshCustomAnimationState(false) end
popup:Destroy()
end
end)
Cancel.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(CustomAnimMgtContainer, "71829270056766", function()
if State.currentCustomAnimationName ~= "Default" then
local idx = table.find(State.CustomAnimations.Order, State.currentCustomAnimationName)
if idx then table.remove(State.CustomAnimations.Order, idx) end
State.CustomAnimations.Sets[State.currentCustomAnimationName] = nil
State.currentCustomAnimationName = "Default"
State.CustomAnimations.Selected = "Default"
State.SaveCustomAnimations(State.CustomAnimations)
if State.CustomAnimDropdown then
State.CustomAnimDropdown.Refresh(State.CustomAnimations.Order)
State.CustomAnimDropdown.Button.Text = "Default ▼"
end
if State.RefreshCustomAnimUI then State.RefreshCustomAnimUI() end
if State.ApplyCustomAnimIconUI then State.ApplyCustomAnimIconUI() end
if refreshCustomAnimationState then refreshCustomAnimationState(false) end
end
end)
SettingsLib.AddIconButton(CustomAnimMgtContainer, "117761881427472", function()
if State.currentCustomAnimationName == "Default" then return end
local popup, content = CreatePopup("Rename Animation")
local In = CreateInput(content, "New Name...", State.currentCustomAnimationName)
local Save = CreateButton(content, "RENAME", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.6, 0))
local Cancel = CreateButton(content, "CANCEL", Color3.fromRGB(50, 50, 50), UDim2.new(0.55, 0, 0.6, 0))
Cancel.TextColor3 = Color3.new(1,1,1)
Save.MouseButton1Click:Connect(function()
if In.Text ~= "" and not State.CustomAnimations.Sets[In.Text] then
local idx = table.find(State.CustomAnimations.Order, State.currentCustomAnimationName)
if idx then State.CustomAnimations.Order[idx] = In.Text end
State.CustomAnimations.Sets[In.Text] = State.CustomAnimations.Sets[State.currentCustomAnimationName]
State.CustomAnimations.Sets[State.currentCustomAnimationName] = nil
State.currentCustomAnimationName = In.Text
State.CustomAnimations.Selected = In.Text
State.SaveCustomAnimations(State.CustomAnimations)
if State.CustomAnimDropdown then
State.CustomAnimDropdown.Refresh(State.CustomAnimations.Order)
State.CustomAnimDropdown.Button.Text = State.currentCustomAnimationName .. " ▼"
end
if State.RefreshCustomAnimUI then State.RefreshCustomAnimUI() end
if State.ApplyCustomAnimIconUI then State.ApplyCustomAnimIconUI() end
if refreshCustomAnimationState then refreshCustomAnimationState(false) end
popup:Destroy()
end
end)
Cancel.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(CustomAnimMgtContainer, "107588515524752", function()
local currentSet = State.CustomAnimations.Sets[State.currentCustomAnimationName]
local data = {
Type = "CustomAnimationSet",
Name = State.currentCustomAnimationName,
Data = currentSet
}
local json = HttpService:JSONEncode(data)
local popup, content = CreatePopup("Export Animations", UDim2.fromOffset(320, 240))
local box = CreateInput(content, "", json, true)
box.Size = UDim2.new(0.9, 0, 0, 130)
box.TextEditable = false
local copy = CreateButton(content, "COPY TO CLIPBOARD", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
copy.MouseButton1Click:Connect(function()
setclipboard(json)
copy.Text = "COPIED!"
task.delay(1, function() copy.Text = "COPY TO CLIPBOARD" end)
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "X"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.Parent = popup
close.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(CustomAnimMgtContainer, "78317476576895", function()
local popup, content = CreatePopup("Import Animations", UDim2.fromOffset(320, 240))
local box = CreateInput(content, "Paste Animation JSON here...", "", true)
box.Size = UDim2.new(0.9, 0, 0, 130)
local imp = CreateButton(content, "IMPORT DATA", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
imp.MouseButton1Click:Connect(function()
local s, d = pcall(function() return HttpService:JSONDecode(box.Text) end)
if s and type(d) == "table" then
if d.Type and d.Type ~= "CustomAnimationSet" then
getgenv().Notify({ Title = "Error", Content = "Backup type mismatch!", Duration = 3 })
return
end
if type(d.Data) ~= "table" then
getgenv().Notify({ Title = "Error", Content = "Invalid JSON", Duration = 3 })
return
end
State.CustomAnimations = NormalizeCustomAnimationData(State.CustomAnimations)
local sourceName = d.Name or "Imported"
local targetName = MakeUniqueSetName(State.CustomAnimations.Sets, sourceName)
local imported = d.Data
imported.__meta = imported.__meta or {}
if imported.__meta.IconImage == nil then imported.__meta.IconImage = DEFAULT_IDLE_ICON_ID end
if imported.__meta.IconColor == nil then imported.__meta.IconColor = ColorToTable(DEFAULT_IDLE_ICON_COLOR) end
State.CustomAnimations.Sets[targetName] = imported
table.insert(State.CustomAnimations.Order, targetName)
State.currentCustomAnimationName = targetName
State.CustomAnimations.Selected = targetName
State.SaveCustomAnimations(State.CustomAnimations)
if State.CustomAnimDropdown then
State.CustomAnimDropdown.Refresh(State.CustomAnimations.Order)
State.CustomAnimDropdown.Button.Text = State.currentCustomAnimationName .. " ▼"
end
if State.RefreshCustomAnimUI then State.RefreshCustomAnimUI() end
if State.ApplyCustomAnimIconUI then State.ApplyCustomAnimIconUI() end
if refreshCustomAnimationState then refreshCustomAnimationState(false) end
popup:Destroy()
getgenv().Notify({ Title = "7yd7 | Animation", Content = "✅ Imported custom animations", Duration = 3 })
else
getgenv().Notify({ Title = "Error", Content = "Invalid JSON", Duration = 3 })
end
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "x"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.Parent = popup
close.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
function GetCurrentCustomAnimMeta()
local set = State.CustomAnimations.Sets[State.currentCustomAnimationName]
if not set then return nil end
set.__meta = set.__meta or {}
if set.__meta.IconImage == nil then set.__meta.IconImage = DEFAULT_IDLE_ICON_ID end
if set.__meta.IconColor == nil then set.__meta.IconColor = ColorToTable(DEFAULT_IDLE_ICON_COLOR) end
return set.__meta
end
State.ApplyCustomAnimIconUI = function()
if not State.CustomAnimIconControl or not State.CustomAnimIconControl.SetValue then return end
local meta = GetCurrentCustomAnimMeta()
if not meta then return end
State.CustomAnimIconControl.SetValue(meta.IconImage or DEFAULT_IDLE_ICON_ID, TableToColor(meta.IconColor or ColorToTable(DEFAULT_IDLE_ICON_COLOR)))
end
do
local meta = GetCurrentCustomAnimMeta() or {}
local currentImage = meta.IconImage or DEFAULT_IDLE_ICON_ID
local currentColor = TableToColor(meta.IconColor or ColorToTable(DEFAULT_IDLE_ICON_COLOR))
State.CustomAnimIconControl = SettingsLib.AddAssetColor(State.CustomAnimTab, "Icon", "Asset ID or URL...", currentImage, currentColor, function(text, color)
local set = State.CustomAnimations.Sets[State.currentCustomAnimationName]
if not set then return end
set.__meta = set.__meta or {}
set.__meta.IconImage = text
set.__meta.IconColor = ColorToTable(color)
State.SaveCustomAnimations(State.CustomAnimations)
if refreshCustomAnimationState then refreshCustomAnimationState(false) end
end)
if State.CustomAnimIconControl and State.CustomAnimIconControl.Item then
State.CustomAnimIconControl.Item.LayoutOrder = 1.5
end
local resetBtn = SettingsLib:Create("ImageButton", {
Parent = State.CustomAnimIconControl.Item,
BackgroundTransparency = 1,
Position = UDim2.new(1, -120, 0.5, -10),
Size = UDim2.fromOffset(20, 20),
Image = "rbxassetid://127493377027615",
ScaleType = Enum.ScaleType.Fit,
ZIndex = 10
})
resetBtn.MouseButton1Click:Connect(function()
local set = State.CustomAnimations.Sets[State.currentCustomAnimationName]
if not set then return end
set.__meta = set.__meta or {}
set.__meta.IconImage = DEFAULT_IDLE_ICON_ID
set.__meta.IconColor = ColorToTable(DEFAULT_IDLE_ICON_COLOR)
State.SaveCustomAnimations(State.CustomAnimations)
if State.CustomAnimIconControl and State.CustomAnimIconControl.SetValue then
State.CustomAnimIconControl.SetValue(DEFAULT_IDLE_ICON_ID, DEFAULT_IDLE_ICON_COLOR)
end
if refreshCustomAnimationState then refreshCustomAnimationState(false) end
end)
end
State.CustomAnimUIElems = {}
function CreateAnimSetUI(folder, cat, name)
local item = SettingsLib.AddItem(folder, cat .. " - " .. name, "Current ID: 0")
local resetBtn = SettingsLib:Create("ImageButton", {
Parent = item,
BackgroundTransparency = 1,
Position = UDim2.new(1, -70, 0.5, -10),
Size = UDim2.fromOffset(20, 20),
Image = "rbxassetid://127493377027615",
ScaleType = Enum.ScaleType.Fit,
ZIndex = 10
})
local editBtn = SettingsLib:Create("ImageButton", {
Parent = item,
BackgroundTransparency = 1,
Position = UDim2.new(1, -40, 0.5, -10),
Size = UDim2.fromOffset(20, 20),
Image = "rbxassetid://117761881427472",
ScaleType = Enum.ScaleType.Fit,
ZIndex = 10
})
resetBtn.MouseButton1Click:Connect(function()
if State.currentCustomAnimationName == "Default" then return end
if State.CustomAnimations.Sets[State.currentCustomAnimationName] then
if not State.CustomAnimations.Sets[State.currentCustomAnimationName][cat] then
State.CustomAnimations.Sets[State.currentCustomAnimationName][cat] = {}
end
State.CustomAnimations.Sets[State.currentCustomAnimationName][cat][name] = 0
State.SaveCustomAnimations(State.CustomAnimations)
if State.RefreshCustomAnimUI then State.RefreshCustomAnimUI() end
if refreshCustomAnimationState then refreshCustomAnimationState(true) end
end
end)
editBtn.MouseButton1Click:Connect(function()
State.enterCustomAnimationEditor(cat, name)
end)
table.insert(State.CustomAnimUIElems, { item = item, cat = cat, name = name })
end
State.CustomAnimFolders = {}
State.CustomAnimFolders.Idle = SettingsLib.AddFolder(State.CustomAnimTab, "Idle Animations")
State.CustomAnimFolders.Idle.Parent.LayoutOrder = 2
CreateAnimSetUI(State.CustomAnimFolders.Idle, "idle", "Animation1")
CreateAnimSetUI(State.CustomAnimFolders.Idle, "idle", "Animation2")
State.CustomAnimFolders.Movement = SettingsLib.AddFolder(State.CustomAnimTab, "Movement Animations")
State.CustomAnimFolders.Movement.Parent.LayoutOrder = 3
CreateAnimSetUI(State.CustomAnimFolders.Movement, "walk", "WalkAnim")
CreateAnimSetUI(State.CustomAnimFolders.Movement, "run", "RunAnim")
CreateAnimSetUI(State.CustomAnimFolders.Movement, "jump", "JumpAnim")
CreateAnimSetUI(State.CustomAnimFolders.Movement, "fall", "FallAnim")
CreateAnimSetUI(State.CustomAnimFolders.Movement, "climb", "ClimbAnim")
CreateAnimSetUI(State.CustomAnimFolders.Movement, "swimidle", "SwimIdle")
CreateAnimSetUI(State.CustomAnimFolders.Movement, "swim", "Swim")
State.RefreshCustomAnimUI = function()
local set = State.CustomAnimations.Sets[State.currentCustomAnimationName]
if not set then return end
for _, elem in pairs(State.CustomAnimUIElems) do
local desc = elem.item:FindFirstChild("Desc")
if desc then
local val = set[elem.cat] and set[elem.cat][elem.name] or 0
desc.Text = "Current ID: " .. tostring(val)
end
end
end
State.RefreshCustomAnimUI()
State.PageTab = SettingsLib.CreateTab("Page", 5)
function GetEmotePageNames()
return State.EmotePages.Order
end
function GetAnimationPageNames()
return State.AnimationPages.Order
end
SettingsLib.AddItem(State.PageTab, "Page Profiles", "Pages allow you to save different favorite sets. Switch pages to quickly change your favorite wheel loadout.")
SettingsLib.AddItem(State.PageTab, "Emote Profiles", "Manage your favorite emote profiles")
State.PageDropdown = SettingsLib.AddDropdown(State.PageTab, "Select Emote Page", GetEmotePageNames(), State.currentEmotePageName, function(v)
SwitchEmotePage(v)
State.SaveEmotePages(State.EmotePages)
end)
local EmotePageMgtItem = SettingsLib.AddItem(State.PageTab, "Emote Page Management", " ")
EmotePageMgtItem.BackgroundColor3 = Color3.fromRGB(35, 38, 42)
EmotePageMgtItem.Size = UDim2.new(0.95, 0, 0, 70)
for _, v in pairs(EmotePageMgtItem:GetChildren()) do if v.Name == "Title" or v.Name == "Desc" then v:Destroy() end end
local EmotePageMgtContainer = Instance.new("Frame")
EmotePageMgtContainer.Parent = EmotePageMgtItem
EmotePageMgtContainer.BackgroundTransparency = 1
EmotePageMgtContainer.Size = UDim2.new(1, 0, 1, 0)
local EmotePageLayout = Instance.new("UIListLayout")
EmotePageLayout.FillDirection = Enum.FillDirection.Horizontal
EmotePageLayout.Padding = UDim.new(0, 15)
EmotePageLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
EmotePageLayout.VerticalAlignment = Enum.VerticalAlignment.Center
EmotePageLayout.Parent = EmotePageMgtContainer
SettingsLib.AddIconButton(EmotePageMgtContainer, "108445456753346", function()
local popup, content = CreatePopup("Create Emote Page")
local In = CreateInput(content, "Page Name...")
local Save = CreateButton(content, "SAVE", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.6, 0))
local Cancel = CreateButton(content, "CANCEL", Color3.fromRGB(50, 50, 50), UDim2.new(0.55, 0, 0.6, 0))
Save.MouseButton1Click:Connect(function()
if In.Text ~= "" and not State.EmotePages.Sets[In.Text] then
State.EmotePages.Sets[In.Text] = {}
table.insert(State.EmotePages.Order, In.Text)
table.sort(State.EmotePages.Order, function(a, b)
if a == "Default" then return true end
if b == "Default" then return false end
return a:lower() < b:lower()
end)
State.SaveEmotePages(State.EmotePages)
if State.PageDropdown then State.PageDropdown.Refresh(GetEmotePageNames()) end
SwitchEmotePage(In.Text)
if State.PageDropdown then State.PageDropdown.Button.Text = State.currentEmotePageName .. " ▼" end
popup:Destroy()
end
end)
Cancel.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(EmotePageMgtContainer, "71829270056766", function()
if State.currentEmotePageName ~= "Default" then
local idx = table.find(State.EmotePages.Order, State.currentEmotePageName)
if idx then table.remove(State.EmotePages.Order, idx) end
State.EmotePages.Sets[State.currentEmotePageName] = nil
State.currentEmotePageName = "Default"
State.EmotePages.Selected = "Default"
State.SaveEmotePages(State.EmotePages)
if State.PageDropdown then
State.PageDropdown.Refresh(GetEmotePageNames())
State.PageDropdown.Button.Text = "Default ▼"
end
SwitchEmotePage("Default")
end
end)
SettingsLib.AddIconButton(EmotePageMgtContainer, "117761881427472", function()
if State.currentEmotePageName == "Default" then return end
local popup, content = CreatePopup("Rename Emote Page")
local In = CreateInput(content, "New Name...", State.currentEmotePageName)
local Save = CreateButton(content, "RENAME", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.6, 0))
local Cancel = CreateButton(content, "CANCEL", Color3.fromRGB(50, 50, 50), UDim2.new(0.55, 0, 0.6, 0))
Save.MouseButton1Click:Connect(function()
if In.Text ~= "" and not State.EmotePages.Sets[In.Text] then
local idx = table.find(State.EmotePages.Order, State.currentEmotePageName)
if idx then State.EmotePages.Order[idx] = In.Text end
State.EmotePages.Sets[In.Text] = State.EmotePages.Sets[State.currentEmotePageName]
State.EmotePages.Sets[State.currentEmotePageName] = nil
State.currentEmotePageName = In.Text
State.EmotePages.Selected = In.Text
State.SaveEmotePages(State.EmotePages)
if State.PageDropdown then
State.PageDropdown.Refresh(GetEmotePageNames())
State.PageDropdown.Button.Text = State.currentEmotePageName .. " ▼"
end
popup:Destroy()
end
end)
Cancel.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(EmotePageMgtContainer, "107588515524752", function()
local currentSet = State.EmotePages.Sets[State.currentEmotePageName]
local data = { Type = "EmotePageSet", Name = State.currentEmotePageName, Data = currentSet }
local json = HttpService:JSONEncode(data)
local popup, content = CreatePopup("Export Emote Page", UDim2.fromOffset(320, 240))
local box = CreateInput(content, "", json, true)
box.Size = UDim2.new(0.9, 0, 0, 130)
box.TextEditable = false
local copy = CreateButton(content, "COPY TO CLIPBOARD", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
copy.MouseButton1Click:Connect(function()
setclipboard(json)
copy.Text = "COPIED!"
task.delay(1, function() copy.Text = "COPY TO CLIPBOARD" end)
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "×"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.Parent = popup
close.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(EmotePageMgtContainer, "78317476576895", function()
local popup, content = CreatePopup("Import Emote Page", UDim2.fromOffset(320, 240))
local box = CreateInput(content, "Paste Page JSON here...", "", true)
box.Size = UDim2.new(0.9, 0, 0, 130)
local imp = CreateButton(content, "IMPORT DATA", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
imp.MouseButton1Click:Connect(function()
local s, d = pcall(function() return HttpService:JSONDecode(box.Text) end)
if s and type(d) == "table" and d.Type == "EmotePageSet" and type(d.Data) == "table" then
local targetName = MakeUniqueSetName(State.EmotePages.Sets, d.Name or "Imported")
State.EmotePages.Sets[targetName] = d.Data
table.insert(State.EmotePages.Order, targetName)
State.currentEmotePageName = targetName
State.EmotePages.Selected = targetName
State.SaveEmotePages(State.EmotePages)
if State.PageDropdown then
State.PageDropdown.Refresh(GetEmotePageNames())
State.PageDropdown.Button.Text = State.currentEmotePageName .. " ▼"
end
SwitchEmotePage(targetName)
popup:Destroy()
getgenv().Notify({ Title = "7yd7 | Page", Content = "✅ Imported Emote page", Duration = 3 })
else
getgenv().Notify({ Title = "Error", Content = "Invalid Emote Page JSON", Duration = 3 })
end
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "×"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.Parent = popup
close.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddItem(State.PageTab, "Animation Profiles", "Manage your favorite animation profiles")
State.AnimationPageDropdown = SettingsLib.AddDropdown(State.PageTab, "Select Animation Page", GetAnimationPageNames(), State.currentAnimationPageName, function(v)
SwitchAnimationPage(v)
State.SaveAnimationPages(State.AnimationPages)
end)
local AnimPageMgtItem = SettingsLib.AddItem(State.PageTab, "Animation Page Management", " ")
AnimPageMgtItem.BackgroundColor3 = Color3.fromRGB(35, 38, 42)
AnimPageMgtItem.Size = UDim2.new(0.95, 0, 0, 70)
for _, v in pairs(AnimPageMgtItem:GetChildren()) do if v.Name == "Title" or v.Name == "Desc" then v:Destroy() end end
local AnimPageMgtContainer = Instance.new("Frame")
AnimPageMgtContainer.Parent = AnimPageMgtItem
AnimPageMgtContainer.BackgroundTransparency = 1
AnimPageMgtContainer.Size = UDim2.new(1, 0, 1, 0)
local AnimPageLayout = Instance.new("UIListLayout")
AnimPageLayout.FillDirection = Enum.FillDirection.Horizontal
AnimPageLayout.Padding = UDim.new(0, 15)
AnimPageLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
AnimPageLayout.VerticalAlignment = Enum.VerticalAlignment.Center
AnimPageLayout.Parent = AnimPageMgtContainer
SettingsLib.AddIconButton(AnimPageMgtContainer, "108445456753346", function()
local popup, content = CreatePopup("Create Animation Page")
local In = CreateInput(content, "Page Name...")
local Save = CreateButton(content, "SAVE", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.6, 0))
local Cancel = CreateButton(content, "CANCEL", Color3.fromRGB(50, 50, 50), UDim2.new(0.55, 0, 0.6, 0))
Save.MouseButton1Click:Connect(function()
if In.Text ~= "" and not State.AnimationPages.Sets[In.Text] then
State.AnimationPages.Sets[In.Text] = {}
table.insert(State.AnimationPages.Order, In.Text)
table.sort(State.AnimationPages.Order, function(a, b)
if a == "Default" then return true end
if b == "Default" then return false end
return a:lower() < b:lower()
end)
State.SaveAnimationPages(State.AnimationPages)
if State.AnimationPageDropdown then State.AnimationPageDropdown.Refresh(GetAnimationPageNames()) end
SwitchAnimationPage(In.Text)
if State.AnimationPageDropdown then State.AnimationPageDropdown.Button.Text = State.currentAnimationPageName .. " ▼" end
popup:Destroy()
end
end)
Cancel.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(AnimPageMgtContainer, "71829270056766", function()
if State.currentAnimationPageName ~= "Default" then
local idx = table.find(State.AnimationPages.Order, State.currentAnimationPageName)
if idx then table.remove(State.AnimationPages.Order, idx) end
State.AnimationPages.Sets[State.currentAnimationPageName] = nil
State.currentAnimationPageName = "Default"
State.AnimationPages.Selected = "Default"
State.SaveAnimationPages(State.AnimationPages)
if State.AnimationPageDropdown then
State.AnimationPageDropdown.Refresh(GetAnimationPageNames())
State.AnimationPageDropdown.Button.Text = "Default ▼"
end
SwitchAnimationPage("Default")
end
end)
SettingsLib.AddIconButton(AnimPageMgtContainer, "117761881427472", function()
if State.currentAnimationPageName == "Default" then return end
local popup, content = CreatePopup("Rename Animation Page")
local In = CreateInput(content, "New Name...", State.currentAnimationPageName)
local Save = CreateButton(content, "RENAME", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.6, 0))
local Cancel = CreateButton(content, "CANCEL", Color3.fromRGB(50, 50, 50), UDim2.new(0.55, 0, 0.6, 0))
Save.MouseButton1Click:Connect(function()
if In.Text ~= "" and not State.AnimationPages.Sets[In.Text] then
local idx = table.find(State.AnimationPages.Order, State.currentAnimationPageName)
if idx then State.AnimationPages.Order[idx] = In.Text end
State.AnimationPages.Sets[In.Text] = State.AnimationPages.Sets[State.currentAnimationPageName]
State.AnimationPages.Sets[State.currentAnimationPageName] = nil
State.currentAnimationPageName = In.Text
State.AnimationPages.Selected = In.Text
State.SaveAnimationPages(State.AnimationPages)
if State.AnimationPageDropdown then
State.AnimationPageDropdown.Refresh(GetAnimationPageNames())
State.AnimationPageDropdown.Button.Text = State.currentAnimationPageName .. " ▼"
end
popup:Destroy()
end
end)
Cancel.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(AnimPageMgtContainer, "107588515524752", function()
local currentSet = State.AnimationPages.Sets[State.currentAnimationPageName]
local data = { Type = "AnimationPageSet", Name = State.currentAnimationPageName, Data = currentSet }
local json = HttpService:JSONEncode(data)
local popup, content = CreatePopup("Export Animation Page", UDim2.fromOffset(320, 240))
local box = CreateInput(content, "", json, true)
box.Size = UDim2.new(0.9, 0, 0, 130)
box.TextEditable = false
local copy = CreateButton(content, "COPY TO CLIPBOARD", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
copy.MouseButton1Click:Connect(function()
setclipboard(json)
copy.Text = "COPIED!"
task.delay(1, function() copy.Text = "COPY TO CLIPBOARD" end)
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "×"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.Parent = popup
close.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
SettingsLib.AddIconButton(AnimPageMgtContainer, "78317476576895", function()
local popup, content = CreatePopup("Import Animation Page", UDim2.fromOffset(320, 240))
local box = CreateInput(content, "Paste Animation Page JSON here...", "", true)
box.Size = UDim2.new(0.9, 0, 0, 130)
local imp = CreateButton(content, "IMPORT DATA", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
imp.MouseButton1Click:Connect(function()
local s, d = pcall(function() return HttpService:JSONDecode(box.Text) end)
if s and type(d) == "table" and d.Type == "AnimationPageSet" and type(d.Data) == "table" then
local targetName = MakeUniqueSetName(State.AnimationPages.Sets, d.Name or "Imported")
State.AnimationPages.Sets[targetName] = d.Data
table.insert(State.AnimationPages.Order, targetName)
State.currentAnimationPageName = targetName
State.AnimationPages.Selected = targetName
State.SaveAnimationPages(State.AnimationPages)
if State.AnimationPageDropdown then
State.AnimationPageDropdown.Refresh(GetAnimationPageNames())
State.AnimationPageDropdown.Button.Text = State.currentAnimationPageName .. " ▼"
end
SwitchAnimationPage(targetName)
popup:Destroy()
getgenv().Notify({ Title = "7yd7 | Page", Content = "✅ Imported Animation page", Duration = 3 })
else
getgenv().Notify({ Title = "Error", Content = "Invalid Animation Page JSON", Duration = 3 })
end
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "×"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.Parent = popup
close.MouseButton1Click:Connect(function() popup:Destroy() end)
end)
local BackupTab = SettingsLib.CreateTab("Backup", 6)
local BackupDesc = SettingsLib.AddItem(BackupTab, "What's included in a backup?", " ")
BackupDesc.LayoutOrder = 1
BackupDesc.Size = UDim2.new(0.95, 0, 0, 110)
for _, v in pairs(BackupDesc:GetChildren()) do if v.Name == "Title" or v.Name == "Desc" then v:Destroy() end end
BackupDesc.BackgroundTransparency = 0
BackupDesc.BackgroundColor3 = Color3.fromRGB(35, 38, 42)
local BackupTitle = Instance.new("TextLabel")
BackupTitle.Parent = BackupDesc
BackupTitle.BackgroundTransparency = 1
BackupTitle.Position = UDim2.new(0, 12, 0, 6)
BackupTitle.Size = UDim2.new(1, -24, 0, 18)
BackupTitle.Font = Enum.Font.GothamBold
BackupTitle.Text = "What's included in a backup?"
BackupTitle.TextColor3 = Color3.fromRGB(200, 200, 200)
BackupTitle.TextSize = 12
BackupTitle.TextXAlignment = Enum.TextXAlignment.Left
local DescList = Instance.new("Frame")
DescList.Parent = BackupDesc
DescList.BackgroundTransparency = 1
DescList.Position = UDim2.new(0, 12, 0, 28)
DescList.Size = UDim2.new(1, -24, 1, -28)
local LayoutDesc = Instance.new("UIListLayout")
LayoutDesc.Parent = DescList
LayoutDesc.Padding = UDim.new(0, 4)
function MakeDescLine(text)
local lbl = Instance.new("TextLabel")
lbl.Parent = DescList
lbl.BackgroundTransparency = 1
lbl.Size = UDim2.new(1, 0, 0, 15)
lbl.AutomaticSize = Enum.AutomaticSize.Y
lbl.TextWrapped = true
lbl.Font = Enum.Font.Gotham
lbl.Text = text
lbl.TextColor3 = Color3.fromRGB(150, 150, 150)
lbl.TextSize = 11
lbl.TextXAlignment = Enum.TextXAlignment.Left
lbl.RichText = true
end
MakeDescLine("• Theme: Saves custom themes")
MakeDescLine("• Settings: Saves HUD layout & values")
MakeDescLine("• Favorite: Saves favorite emotes/anims")
MakeDescLine("• All: Includes everything above")
local ExportItem = SettingsLib.AddItem(BackupTab, "Export Settings", "Save current settings to a file for sharing or later import.")
ExportItem.LayoutOrder = 2
local ExportBtnContainer = Instance.new("Frame")
ExportBtnContainer.Parent = ExportItem
ExportBtnContainer.BackgroundTransparency = 1
ExportBtnContainer.Size = UDim2.new(1, -24, 0, 60)
local expDesc = ExportItem:FindFirstChild("Desc")
if expDesc then
expDesc.Size = UDim2.new(1, -24, 0, 0)
local function updateExpPos()
ExportBtnContainer.Position = UDim2.new(0, 12, 0, expDesc.Position.Y.Offset + expDesc.AbsoluteSize.Y + 12)
end
expDesc:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateExpPos)
updateExpPos()
else
ExportBtnContainer.Position = UDim2.new(0, 12, 0, 32)
end
local ExportLayout = Instance.new("UIGridLayout")
ExportLayout.CellSize = UDim2.new(0.48, 0, 0, 26)
ExportLayout.CellPadding = UDim2.new(0.04, 0, 0, 8)
ExportLayout.SortOrder = Enum.SortOrder.LayoutOrder
ExportLayout.Parent = ExportBtnContainer
function CreateExportBtn(text, color, order)
local btn = Instance.new("TextButton")
btn.LayoutOrder = order
btn.BackgroundColor3 = color
btn.Text = text
btn.Font = Enum.Font.GothamBold
btn.TextColor3 = Color3.new(1,1,1)
btn.TextSize = 11
btn.Parent = ExportBtnContainer
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 6)
corner.Parent = btn
return btn
end
local btnColors = {
dark = Color3.fromRGB(45, 48, 52),
blue = Color3.fromRGB(88, 101, 242)
}
local BtnExportAll = CreateExportBtn("Export All Settings", btnColors.dark, 1)
local BtnExportThemes = CreateExportBtn("Export Themes", btnColors.blue, 2)
local BtnExportSettings = CreateExportBtn("Export Settings", btnColors.blue, 3)
local BtnExportFavorites = CreateExportBtn("Export Favorites", btnColors.blue, 4)
function GetFavoritesData()
local favAnimsStr = "{}"
if isfile and isfile(State.favoriteAnimationsFileName) then
favAnimsStr = readfile(State.favoriteAnimationsFileName)
end
return {
EmotePages = State.EmotePages,
Animations = HttpService:JSONDecode(favAnimsStr) or {}
}
end
BtnExportAll.MouseButton1Click:Connect(function()
local data = {
Type = "All",
Themes = LoadThemes(),
Settings = Config,
Favorites = GetFavoritesData()
}
setclipboard(HttpService:JSONEncode(data))
BtnExportAll.Text = "Copied!"
task.delay(1, function() BtnExportAll.Text = "Export All Settings" end)
end)
BtnExportThemes.MouseButton1Click:Connect(function()
local data = {
Type = "Themes",
Themes = LoadThemes()
}
setclipboard(HttpService:JSONEncode(data))
BtnExportThemes.Text = "Copied!"
task.delay(1, function() BtnExportThemes.Text = "Export Themes" end)
end)
BtnExportSettings.MouseButton1Click:Connect(function()
local data = {
Type = "Settings",
Settings = Config
}
setclipboard(HttpService:JSONEncode(data))
BtnExportSettings.Text = "Copied!"
task.delay(1, function() BtnExportSettings.Text = "Export Settings" end)
end)
BtnExportFavorites.MouseButton1Click:Connect(function()
local data = {
Type = "Favorites",
Favorites = GetFavoritesData()
}
setclipboard(HttpService:JSONEncode(data))
BtnExportFavorites.Text = "Copied!"
task.delay(1, function() BtnExportFavorites.Text = "Export Favorites" end)
end)
local ImportItem = SettingsLib.AddItem(BackupTab, "Import Settings", "Select a backup file to restore your configuration and overwrite current settings.")
ImportItem.LayoutOrder = 3
local ImportBtnContainer = Instance.new("Frame")
ImportBtnContainer.Parent = ImportItem
ImportBtnContainer.BackgroundTransparency = 1
ImportBtnContainer.Size = UDim2.new(1, -24, 0, 60)
local impDesc = ImportItem:FindFirstChild("Desc")
if impDesc then
impDesc.Size = UDim2.new(1, -24, 0, 0)
local function updateImpPos()
ImportBtnContainer.Position = UDim2.new(0, 12, 0, impDesc.Position.Y.Offset + impDesc.AbsoluteSize.Y + 12)
end
impDesc:GetPropertyChangedSignal("AbsoluteSize"):Connect(updateImpPos)
updateImpPos()
else
ImportBtnContainer.Position = UDim2.new(0, 12, 0, 32)
end
local ImportLayout = Instance.new("UIGridLayout")
ImportLayout.CellSize = UDim2.new(0.48, 0, 0, 26)
ImportLayout.CellPadding = UDim2.new(0.04, 0, 0, 8)
ImportLayout.SortOrder = Enum.SortOrder.LayoutOrder
ImportLayout.Parent = ImportBtnContainer
function CreateImportBtn(text, color, order)
local btn = Instance.new("TextButton")
btn.LayoutOrder = order
btn.BackgroundColor3 = color
btn.Text = text
btn.Font = Enum.Font.GothamBold
btn.TextColor3 = Color3.new(1,1,1)
btn.TextSize = 11
btn.Parent = ImportBtnContainer
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 6)
corner.Parent = btn
return btn
end
local BtnImportAll = CreateImportBtn("Import All Settings", btnColors.dark, 1)
local BtnImportThemes = CreateImportBtn("Import Themes", btnColors.blue, 2)
local BtnImportSettings = CreateImportBtn("Import Settings", btnColors.blue, 3)
local BtnImportFavorites = CreateImportBtn("Import Favorites", btnColors.blue, 4)
function HandleImportPrompt(typeStr)
local popup, content = CreatePopup("Import " .. typeStr, UDim2.fromOffset(320, 240))
local box = CreateInput(content, "Paste Backup JSON here...", "", true)
box.Size = UDim2.new(0.9, 0, 0, 130)
local imp = CreateButton(content, "IMPORT DATA", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
imp.MouseButton1Click:Connect(function()
local s, d = pcall(function() return HttpService:JSONDecode(box.Text) end)
if s and type(d) == "table" and d.Type then
if typeStr ~= "All" and d.Type ~= "All" and typeStr ~= d.Type then
getgenv().Notify({Title = "Error", Content = "Backup type mismatch!", Duration = 3})
return
end
if d.Themes and (typeStr == "All" or typeStr == "Themes") then
themes = d.Themes
currentThemeName = themes.Selected or Config.SelectedTheme or "Default"
SaveThemesImplementation(themes)
themeDropdown.Refresh(GetNames())
if themeDropdown and themeDropdown.Button then
themeDropdown.Button.Text = currentThemeName .. " ▼"
end
local themeToApply = themes[currentThemeName] or themes["Default"]
if themeToApply then
State.isApplyingTheme = false
ApplyTheme(themeToApply)
else
warn("7yd7 | Missing Default theme during import fallback")
end
end
if d.Settings and (typeStr == "All" or typeStr == "Settings") then
for k, v in pairs(d.Settings) do Config[k] = v end
SaveConfig()
ApplyUIVisibility()
if applySavedPositions then applySavedPositions() end
if State.RefreshSettingsUI then State.RefreshSettingsUI() end
end
if (d.Favorites or d.EmotePages) and (typeStr == "All" or typeStr == "Favorites") then
local emotesData = d.EmotePages or d.Favorites.Emotes
if emotesData then
if emotesData.Sets then
State.EmotePages = emotesData
else
State.EmotePages.Sets.Default = emotesData
end
State.SaveEmotePages(State.EmotePages)
SwitchEmotePage(State.currentEmotePageName)
end
if d.Favorites and d.Favorites.Animations then
State.favoriteAnimations = d.Favorites.Animations
writefile(State.favoriteAnimationsFileName, HttpService:JSONEncode(d.Favorites.Animations))
State.favoriteSetVersion = State.favoriteSetVersion + 1
end
if State.RefreshUI then State.RefreshUI() end
end
getgenv().Notify({Title = "Success", Content = "Data imported successfully!", Duration = 3})
popup:Destroy()
else
getgenv().Notify({Title = "Error", Content = "Invalid Backup JSON Format!", Duration = 3})
end
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "×"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.Parent = popup
close.MouseButton1Click:Connect(function() popup:Destroy() end)
end
BtnImportAll.MouseButton1Click:Connect(function() HandleImportPrompt("All") end)
BtnImportThemes.MouseButton1Click:Connect(function() HandleImportPrompt("Themes") end)
BtnImportSettings.MouseButton1Click:Connect(function() HandleImportPrompt("Settings") end)
BtnImportFavorites.MouseButton1Click:Connect(function() HandleImportPrompt("Favorites") end)
pcall(function()
SafeLoad("https://raw.githubusercontent.com/7yd7/Hub/Branch/GUIS/count-emote", "Count Emote")
end)
getgenv().Notify({
Title = '7yd7 | Emote',
Content = '⚠️ Script loading...',
Duration = 5
})
local Players = game:GetService("Players")
local player = Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:WaitForChild("Humanoid")
getgenv().OwnedAuthenticEmotes = getgenv().OwnedAuthenticEmotes or {}
function gatherAuthenticEmotes(char)
if not char then return end
local hum = char:WaitForChild("Humanoid", 5)
if not hum then return end
local desc = hum:WaitForChild("HumanoidDescription", 5)
if not desc then return end
local allEmotes = desc:GetEmotes()
local owned = {}
for _, e in ipairs(desc:GetEquippedEmotes()) do
local id = allEmotes[e.Name] and allEmotes[e.Name][1]
if id then
local idNum = tonumber((tostring(id):gsub("rbxassetid://", "")))
if idNum then
table.insert(owned, {
name = e.Name,
id = idNum
})
end
end
end
if #owned > 0 then
getgenv().OwnedAuthenticEmotes = owned
end
end
task.spawn(function() gatherAuthenticEmotes(character) end)
player.CharacterAdded:Connect(gatherAuthenticEmotes)
local UserInputService = game:GetService("UserInputService")
local CoreGui = game:GetService("CoreGui")
RunService.Heartbeat:Connect(function()
local success, menu = pcall(function() return CoreGui.RobloxGui.EmotesMenu.Children end)
if not (success and menu) then return end
pcall(function()
local wheelVisible = menu.Main.EmotesWheel.Visible
if wheelVisible then
State.lastWheelVisibleTime = tick()
end
ToggleContainer.Visible = wheelVisible
end)
local errorMsg = menu:FindFirstChild("ErrorMessage")
if errorMsg and errorMsg.Visible then
if player.Character and player.Character:FindFirstChild("Humanoid") and player.Character.Humanoid.RigType == Enum.HumanoidRigType.R6 then
errorMsg.ErrorText.Text = "Only r15 does not work r6"
elseif tick() - State.lastRadialActionTime < 2 then
errorMsg.Visible = false
end
end
end)
function ErrorMessage(text, duration)
if State.currentTimer then
task.cancel(State.currentTimer)
State.currentTimer = nil
end
local errorMessage = CoreGui.RobloxGui.EmotesMenu.Children.ErrorMessage
local errorText = errorMessage.ErrorText
errorText.Text = text
errorMessage.Visible = true
State.currentTimer = task.delay(duration, function()
errorMessage.Visible = false
State.currentTimer = nil
end)
end
function stopEmotes()
for _, track in ipairs(humanoid:GetPlayingAnimationTracks()) do
track:Stop()
end
end
function getCharacterAndHumanoid()
local character = player.Character
if not character then
return nil, nil
end
local humanoid = character:FindFirstChild("Humanoid")
if not humanoid then
return nil, nil
end
return character, humanoid
end
function urlToId(animationId)
animationId = string.gsub(animationId, "http://www%.roblox%.com/asset/%?id=", "")
animationId = string.gsub(animationId, "rbxassetid://", "")
return animationId
end
function resolveEmoteToAnimationId(emoteId)
local fallbackId = tonumber(emoteId)
if not emoteId or emoteId == "" then return fallbackId end
local objects
local ok = false
local idStr = tostring(emoteId)
for _, url in ipairs({
"rbxassetid://" .. idStr,
"http://www.roblox.com/asset/?id=" .. idStr
}) do
ok, objects = pcall(function()
return game:GetObjects(url)
end)
if ok and type(objects) == "table" and #objects > 0 then
break
end
end
if ok and type(objects) == "table" then
local function findAnimId(obj)
if obj:IsA("Animation") then
local animId = tonumber(urlToId(obj.AnimationId))
if animId and animId > 0 then
return animId
end
end
for _, child in ipairs(obj:GetChildren()) do
local found = findAnimId(child)
if found then return found end
end
return nil
end
local rootObj = objects[1]
if rootObj and rootObj.Parent == nil then
pcall(function() rootObj.Parent = workspace end)
end
if rootObj then
local foundRoot = findAnimId(rootObj)
if foundRoot then
pcall(function() rootObj:Destroy() end)
return foundRoot
end
end
for _, obj in ipairs(objects) do
local found = findAnimId(obj)
pcall(function() obj:Destroy() end)
if found then
return found
end
end
end
return fallbackId
end
function saveFavoritesAnimations()
if writefile then
local jsonData = HttpService:JSONEncode(State.favoriteAnimations)
writefile(State.favoriteAnimationsFileName, jsonData)
end
end
function loadFavoritesAnimations()
if readfile and isfile and isfile(State.favoriteAnimationsFileName) then
local success, result = pcall(function()
local fileContent = readfile(State.favoriteAnimationsFileName)
return HttpService:JSONDecode(fileContent)
end)
if success and type(result) == "table" then
local filtered = {}
for _, fav in pairs(result) do
local idNum = fav and tonumber(fav.id)
if fav and idNum and (idNum > 0 or idNum < -1000) then
if fav.isCustomSet == nil and idNum < 0 then
fav.isCustomSet = true
end
if IsCustomSetData(fav) and not fav.customSetName and type(fav.name) == "string" then
local baseName = fav.name:gsub("%s*%-.*$", "")
fav.customSetName = baseName
end
table.insert(filtered, fav)
end
end
State.favoriteAnimations = filtered
State.favoriteSetVersion = State.favoriteSetVersion + 1
end
end
end
function disconnectAllConnections()
for _, connection in pairs(State.guiConnections) do
if connection then
connection:Disconnect()
end
end
State.guiConnections = {}
if ContextActionService then
ContextActionService:UnbindAction("7yd7_EmoteWheelHotkeys")
end
end
function loadSpeedEmoteConfig()
State.speedEmoteEnabled = Config.EmoteSpeedEnabled
if UI.SpeedBox then
UI.SpeedBox.Text = tostring(Config.EmoteSpeed)
updateSpeedBoxVisibility()
end
end
function extractAssetId(imageUrl)
local assetId = string.match(imageUrl, "Asset&id=(%d+)")
return assetId
end
local isRandomSlotEnabled
local isRandomSlotActive
function isEmoteSearchActive()
return State.currentMode == "emote" and State.emoteSearchTerm and State.emoteSearchTerm ~= ""
end
function isAnimationSearchActive()
return State.currentMode == "animation" and State.animationSearchTerm and State.animationSearchTerm ~= ""
end
function isSearchActive()
return isEmoteSearchActive() or isAnimationSearchActive()
end
function shouldRandomSlotBeShown()
if Config.RandomEnabled ~= true then return false end
if State.currentMode == "emote" then
return not isEmoteSearchActive()
elseif State.currentMode == "animation" then
return not isAnimationSearchActive()
end
return false
end
function getFirstPageSize()
if shouldRandomSlotBeShown() then
return math.max(State.itemsPerPage - 1, 1)
end
return State.itemsPerPage
end
isRandomSlotEnabled = function()
return Config.RandomEnabled == true
end
function calcPagesForList(count, isFirstList)
if count <= 0 then return 0 end
if isFirstList then
local first = getFirstPageSize()
if count <= first then return 1 end
return 1 + math.ceil((count - first) / State.itemsPerPage)
end
return math.ceil(count / State.itemsPerPage)
end
function getCategoryStats()
local stats = {}
local randomCaptured = false
local shouldShowRandom = shouldRandomSlotBeShown()
local authenticEmotes = (Config.AuthenticFirstPage and State.currentMode == "emote") and (getgenv().OwnedAuthenticEmotes or {}) or {}
if #authenticEmotes > 0 then
local pages = calcPagesForList(#authenticEmotes, false)
table.insert(stats, { name = "Authentic", list = authenticEmotes, pages = pages, hasRandom = false })
end
local favoritesToUse = (State.currentMode == "animation") and (_G.filteredFavoritesAnimationsForDisplay or State.favoriteAnimations) or (_G.filteredFavoritesForDisplay or State.favoriteEmotes)
if #favoritesToUse > 0 then
local hasRandom = not randomCaptured and shouldShowRandom
if hasRandom then randomCaptured = true end
local pages = calcPagesForList(#favoritesToUse, hasRandom)
table.insert(stats, { name = "Favorites", list = favoritesToUse, pages = pages, hasRandom = hasRandom })
end
local normalList = {}
if State.currentMode == "animation" then
normalList = State.animationPageCache.normal or {}
else
normalList = State.emotePageCache.normal or {}
end
if #normalList > 0 then
local hasRandom = not randomCaptured and shouldShowRandom
if hasRandom then randomCaptured = true end
local pages = calcPagesForList(#normalList, hasRandom)
table.insert(stats, { name = "Normal", list = normalList, pages = pages, hasRandom = hasRandom })
end
return stats
end
isRandomSlotActive = function()
if not shouldRandomSlotBeShown() then return false end
local categories = getCategoryStats()
local totalPages = 0
for _, cat in ipairs(categories) do
if cat.hasRandom then
return State.currentPage == totalPages + 1
end
totalPages = totalPages + cat.pages
end
return false
end
function getPageSize(pageNumber, isFirstList)
if isFirstList and pageNumber == 1 then
return getFirstPageSize()
end
return State.itemsPerPage
end
function getListSlice(list, pageNumber, isFirstList)
local pageSize = getPageSize(pageNumber, isFirstList)
local startIndex
if isFirstList and pageNumber == 1 then
startIndex = 1
elseif isFirstList then
startIndex = getFirstPageSize() + (pageNumber - 2) * State.itemsPerPage + 1
else
startIndex = (pageNumber - 1) * State.itemsPerPage + 1
end
local endIndex = math.min(startIndex + pageSize - 1, #list)
local items = {}
for i = startIndex, endIndex do
if list[i] then table.insert(items, list[i]) end
end
return items
end
function getRandomSourceList()
if Config.RandomEnabled == false then
return {}
end
if State.favoriteEnabled then
if State.currentMode == "animation" then
return State.filteredAnimations
end
return State.filteredEmotes
end
if Config.RandomMode == "Favorites" then
if State.currentMode == "animation" then
return _G.filteredFavoritesAnimationsForDisplay or State.favoriteAnimations
end
return _G.filteredFavoritesForDisplay or State.favoriteEmotes
end
if State.currentMode == "animation" then
return State.filteredAnimations
end
return State.filteredEmotes
end
function pickRandomItem()
local list = getRandomSourceList() or {}
if #list == 0 then return nil end
return list[math.random(1, #list)]
end
function pickRandomItemForMode()
local list = getRandomSourceList() or {}
if #list == 0 then return nil end
if State.currentMode == "animation" then
local filtered = {}
for _, item in ipairs(list) do
if item.bundledItems then
table.insert(filtered, item)
end
end
if #filtered == 0 then return nil end
return filtered[math.random(1, #filtered)]
end
return list[math.random(1, #list)]
end
function updateRandomSlotBlocker(frontFrame, enable)
if not frontFrame then return end
local slot = frontFrame:FindFirstChild("1")
if not slot or not slot:IsA("ImageLabel") then return end
local blocker = slot:FindFirstChild("RandomBlocker")
if enable then
if not blocker then
blocker = Instance.new("ImageButton")
blocker.Name = "RandomBlocker"
blocker.BackgroundTransparency = 1
blocker.Size = UDim2.new(1, 0, 1, 0)
blocker.Position = UDim2.new(0, 0, 0, 0)
blocker.AutoButtonColor = false
blocker.ZIndex = slot.ZIndex + 10
blocker.Parent = slot
else
blocker.ZIndex = slot.ZIndex + 10
end
blocker.Active = true
else
if blocker then blocker:Destroy() end
if State.randomSlotBlockerConn then
State.randomSlotBlockerConn:Disconnect()
State.randomSlotBlockerConn = nil
end
end
end
function clearCustomHitboxes()
if State.randomSlotBlockerConn then
State.randomSlotBlockerConn:Disconnect()
State.randomSlotBlockerConn = nil
end
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if not success or not frontFrame then return end
local slot1 = frontFrame:FindFirstChild("1")
if slot1 then
local blocker = slot1:FindFirstChild("RandomBlocker")
if blocker then blocker:Destroy() end
end
for _, child in pairs(frontFrame:GetChildren()) do
if child:IsA("ImageLabel") then
child.Active = false
end
end
frontFrame.Active = true
end
function applyEmotesButtonsActiveState()
end
function setEmotesButtonsActiveForFavorites()
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if not success or not frontFrame then return end
for _, child in pairs(frontFrame:GetChildren()) do
if child:IsA("ImageLabel") then
child.Active = true
end
end
frontFrame.Active = true
end
function updateScriptPriorityOverlay()
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if not success or not frontFrame then return end
local enable = (State.favoriteEnabled or State.currentMode == "animation" or State.customAnimationEditorActive)
local blocker = frontFrame:FindFirstChild("ScriptPriorityBlocker")
if enable then
if not blocker then
blocker = Instance.new("ImageButton")
blocker.Name = "ScriptPriorityBlocker"
blocker.BackgroundTransparency = 1
blocker.Size = UDim2.new(1, 0, 1, 0)
blocker.Position = UDim2.new(0, 0, 0, 0)
blocker.AutoButtonColor = false
blocker.ZIndex = 9999
blocker.Parent = frontFrame
blocker.InputBegan:Connect(function(input)
if State.hudEditorActive then return end
if input.UserInputType ~= Enum.UserInputType.MouseButton1 and input.UserInputType ~= Enum.UserInputType.Touch then return end
local okWheel, emotesWheel = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel
end)
if not (okWheel and emotesWheel) then return end
if not emotesWheel.Visible then return end
local actualPos = Vector2.new(input.Position.X, input.Position.Y)
local absPos = emotesWheel.AbsolutePosition
local absSize = emotesWheel.AbsoluteSize
local inXBounds = (actualPos.X >= absPos.X) and (actualPos.X <= absPos.X + absSize.X)
local inYBounds = (actualPos.Y >= absPos.Y) and (actualPos.Y <= absPos.Y + absSize.Y)
if not (inXBounds and inYBounds) then return end
local center = absPos + (absSize / 2)
local dx = actualPos.X - center.X
local dy = actualPos.Y - center.Y
local distance = math.sqrt(dx*dx + dy*dy)
local radius = math.min(absSize.X, absSize.Y) * 0.5
if distance > radius then return end
local dynamicDeadzone = radius * 0.2
if distance < dynamicDeadzone then return end
local sectorAngle = 360 / 8
local angle = math.deg(math.atan2(dy, dx))
local correctedAngle = (angle + 90 + (sectorAngle / 2)) % 360
local index = math.floor(correctedAngle / sectorAngle) + 1
if not (State.customAnimationEditorActive or State.favoriteEnabled or State.currentMode == "animation" or (index == 1 and isRandomSlotActive())) then return end
handleSectorAction(index)
end)
end
blocker.Active = true
else
if blocker then blocker:Destroy() end
end
end
function applyRandomSlotVisual(frontFrame)
if not frontFrame then return end
local slot = frontFrame:FindFirstChild("1")
if slot and slot:IsA("ImageLabel") then
if not isRandomSlotEnabled() then
AnimationSystem.ResetRandomSlot(frontFrame)
return
end
if slot.Image ~= RANDOM_SLOT_ICON then
slot.Image = RANDOM_SLOT_ICON
end
if slot.ImageColor3 ~= RANDOM_SLOT_COLOR then
slot.ImageColor3 = RANDOM_SLOT_COLOR
end
if State.currentMode == "emote" then
updateRandomSlotBlocker(frontFrame, true)
else
updateRandomSlotBlocker(frontFrame, false)
end
local idValue = slot:FindFirstChild("AnimationID")
if idValue then idValue:Destroy() end
local favoriteIcon = slot:FindFirstChild("FavoriteIcon")
if favoriteIcon then favoriteIcon:Destroy() end
end
end
function resetRandomSlotColor(frontFrame)
if not frontFrame then return end
local slot = frontFrame:FindFirstChild("1")
if slot and slot:IsA("ImageLabel") then
if slot.ImageColor3 == RANDOM_SLOT_COLOR then
slot.ImageColor3 = Color3.new(1, 1, 1)
end
if slot.Image == RANDOM_SLOT_ICON then
slot.Image = ""
end
end
updateRandomSlotBlocker(frontFrame, false)
if State.randomSpamConn then
State.randomSpamConn:Disconnect()
State.randomSpamConn = nil
end
end
function applySearchSlot1Image()
pcall(function()
local frontFrame = game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
local slot1 = frontFrame and frontFrame:FindFirstChild("1")
local slot2 = frontFrame and frontFrame:FindFirstChild("2")
if slot1 and slot1:IsA("ImageLabel") and slot2 and slot2:IsA("ImageLabel") then
local img2 = slot2.Image
if img2 and img2 ~= "" then
slot1.Image = img2
end
end
end)
end
function bumpImageUpdateToken()
State.imageUpdateToken = State.imageUpdateToken + 1
end
local ContentProvider = game:GetService("ContentProvider")
function preloadThumbnail(url)
if not url or url == "" then return end
task.spawn(function()
pcall(function()
ContentProvider:PreloadAsync({Instance.new("ImageLabel", {Image = url})})
end)
end)
end
function enforceImages()
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if not success or not frontFrame then return end
local token = State.imageUpdateToken
for slotName, targetImg in pairs(State.targetImages) do
local slot = frontFrame:FindFirstChild(slotName)
if slot and slot:IsA("ImageLabel") then
if slot.Image ~= targetImg then
slot.Image = targetImg
end
if slotName == "1" and isRandomSlotActive() then
if slot.ImageColor3 ~= RANDOM_SLOT_COLOR then
slot.ImageColor3 = RANDOM_SLOT_COLOR
end
end
end
end
end
function spamRandomSlotVisual(frontFrame, token)
if not frontFrame then return end
State.targetImages["1"] = RANDOM_SLOT_ICON
enforceImages()
end
function spamAnimationImages(frontFrame, imageMap, token)
if not frontFrame then return end
for k, v in pairs(imageMap or {}) do
State.targetImages[k] = v
end
enforceImages()
end
function getEmoteName(assetId)
local success, productInfo = pcall(function()
return game:GetService("MarketplaceService"):GetProductInfo(tonumber(assetId))
end)
if success and productInfo then
return productInfo.Name
else
return "Emote_" .. tostring(assetId)
end
end
isInFavorites = function(assetId)
if not assetId then return false end
if State.favoriteSetBuiltVersion ~= State.favoriteSetVersion then
State.favoriteEmoteSet = {}
for _, favorite in pairs(State.favoriteEmotes) do
if favorite.id then
State.favoriteEmoteSet[tostring(favorite.id)] = true
end
end
State.favoriteAnimationSet = {}
for _, favorite in pairs(State.favoriteAnimations) do
if favorite.id then
State.favoriteAnimationSet[tostring(favorite.id)] = true
end
end
State.favoriteSetBuiltVersion = State.favoriteSetVersion
end
if State.currentMode == "animation" then
return State.favoriteAnimationSet[tostring(assetId)] == true
end
return State.favoriteEmoteSet[tostring(assetId)] == true
end
function rebuildEmoteNormalCache()
if State.emotePageCache.version == State.emoteCacheVersion and State.emotePageCache.favVersion == State.favoriteSetVersion then
return
end
if State.favoriteSetBuiltVersion ~= State.favoriteSetVersion then
State.favoriteEmoteSet = {}
for _, favorite in pairs(State.favoriteEmotes) do
State.favoriteEmoteSet[tostring(favorite.id)] = true
end
State.favoriteAnimationSet = {}
for _, favorite in pairs(State.favoriteAnimations) do
State.favoriteAnimationSet[tostring(favorite.id)] = true
end
State.favoriteSetBuiltVersion = State.favoriteSetVersion
end
local normal = {}
for _, emote in ipairs(State.filteredEmotes) do
if not State.favoriteEmoteSet[tostring(emote.id)] then
table.insert(normal, emote)
end
end
State.emotePageCache.normal = normal
State.emotePageCache.version = State.emoteCacheVersion
State.emotePageCache.favVersion = State.favoriteSetVersion
end
function rebuildAnimationNormalCache()
if State.animationPageCache.version == State.animationCacheVersion and State.animationPageCache.favVersion == State.favoriteSetVersion then
return
end
if State.favoriteSetBuiltVersion ~= State.favoriteSetVersion then
State.favoriteEmoteSet = {}
for _, favorite in pairs(State.favoriteEmotes) do
State.favoriteEmoteSet[tostring(favorite.id)] = true
end
State.favoriteAnimationSet = {}
for _, favorite in pairs(State.favoriteAnimations) do
State.favoriteAnimationSet[tostring(favorite.id)] = true
end
State.favoriteSetBuiltVersion = State.favoriteSetVersion
end
local normal = {}
for _, animation in ipairs(State.filteredAnimations) do
if not State.favoriteAnimationSet[tostring(animation.id)] then
table.insert(normal, animation)
end
end
State.animationPageCache.normal = normal
State.animationPageCache.version = State.animationCacheVersion
State.animationPageCache.favVersion = State.favoriteSetVersion
end
function getCustomSetIcon(setName)
local set = State.CustomAnimations and State.CustomAnimations.Sets and State.CustomAnimations.Sets[setName]
local meta = set and set.__meta or {}
local iconImage = meta.IconImage or DEFAULT_IDLE_ICON_ID
local iconColor = TableToColor(meta.IconColor or ColorToTable(DEFAULT_IDLE_ICON_COLOR))
return iconImage, iconColor
end
function IsCustomSetData(data)
if not data then return false end
if data.isCustomSet then return true end
local idNum = tonumber(data.id)
return idNum and idNum < 0 or false
end
function GetCustomSetName(data)
if not data then return nil end
local name = data.customSetName or data.name
if type(name) == "string" then
name = name:gsub("%s*%-.*$", "")
end
return name
end
function updateAnimationImages(currentPageAnimations, randomActive)
local token = State.imageUpdateToken
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if not success or not frontFrame then
return
end
if randomActive then
applyRandomSlotVisual(frontFrame)
State.targetImages = {["1"] = RANDOM_SLOT_ICON}
spamRandomSlotVisual(frontFrame, token)
else
State.targetImages = {}
resetRandomSlotColor(frontFrame)
end
local startSlot = randomActive and 2 or 1
local imageMap = {}
local newTargetImages = {}
if randomActive then
newTargetImages["1"] = RANDOM_SLOT_ICON
end
for i = 1, 12 do
if i >= startSlot then
local listIndex = randomActive and (i - 1) or i
local animationData = currentPageAnimations[listIndex]
if animationData and animationData.id then
local image = "rbxthumb://type=BundleThumbnail&id=" .. tostring(animationData.id) .. "&w=420&h=420"
if IsCustomSetData(animationData) then
local customImage = getCustomSetIcon(GetCustomSetName(animationData) or animationData.name)
image = GetAsset(customImage)
end
newTargetImages[tostring(i)] = image
imageMap[tostring(i)] = image
else
newTargetImages[tostring(i)] = ""
imageMap[tostring(i)] = ""
end
end
end
State.targetImages = newTargetImages
for slotName, image in pairs(imageMap) do
local child = frontFrame:FindFirstChild(slotName)
if child and child:IsA("ImageLabel") then
preloadThumbnail(image)
child.Image = image
local listIndex = randomActive and (tonumber(slotName) - 1) or tonumber(slotName)
local animationData = currentPageAnimations[listIndex]
if animationData and animationData.id then
local idValue = child:FindFirstChild("AnimationID") or Instance.new("IntValue")
idValue.Name = "AnimationID"
idValue.Value = tonumber(animationData.id) or 0
idValue.Parent = child
if IsCustomSetData(animationData) then
local _, customColor = getCustomSetIcon(GetCustomSetName(animationData) or animationData.name)
child.ImageColor3 = customColor
else
child.ImageColor3 = Color3.new(1, 1, 1)
end
elseif not randomActive and child.ImageColor3 == RANDOM_SLOT_COLOR then
child.ImageColor3 = Color3.new(1, 1, 1)
end
end
end
applyEmotesButtonsActiveState()
end
function updateFavoriteIcon(imageLabel, assetId, isFavorite)
local favoriteIcon = imageLabel:FindFirstChild("FavoriteIcon")
if not favoriteIcon then
favoriteIcon = Instance.new("ImageLabel")
favoriteIcon.Name = "FavoriteIcon"
favoriteIcon.Size = UDim2.new(0.3, 0, 0.3, 0)
favoriteIcon.Position = UDim2.new(0.7, 0, 0, 0)
favoriteIcon.AnchorPoint = Vector2.new(0, 0)
favoriteIcon.BackgroundTransparency = 1
favoriteIcon.ZIndex = imageLabel.ZIndex + 5
favoriteIcon.ScaleType = Enum.ScaleType.Fit
favoriteIcon.Parent = imageLabel
end
if isFavorite then
favoriteIcon.Image = State.favoriteIconId
else
favoriteIcon.Image = State.notFavoriteIconId
end
end
function updateAllFavoriteIcons()
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if success and frontFrame then
if not State.favoriteEnabled then
for _, child in pairs(frontFrame:GetChildren()) do
if child:IsA("ImageLabel") then
local favoriteIcon = child:FindFirstChild("FavoriteIcon")
if favoriteIcon then favoriteIcon:Destroy() end
end
end
return
end
local randomActive = isRandomSlotActive()
for _, child in pairs(frontFrame:GetChildren()) do
if child:IsA("ImageLabel") and child.Image ~= "" and (not randomActive or child.Name ~= "1") then
local assetId
if State.currentMode == "animation" then
local idValue = child:FindFirstChild("AnimationID")
if idValue then
assetId = idValue.Value
end
else
assetId = extractAssetId(child.Image)
end
if assetId then
local isFavorite = isInFavorites(assetId)
updateFavoriteIcon(child, assetId, isFavorite)
end
end
end
applyEmotesButtonsActiveState()
end
end
function updateAnimations()
local character, humanoid = getCharacterAndHumanoid()
if not character or not humanoid then
return
end
local humanoidDescription = humanoid.HumanoidDescription
if not humanoidDescription then
if not State.pendingAnimRetry then
State.pendingAnimRetry = true
task.delay(0.2, function()
State.pendingAnimRetry = false
if State.currentMode == "animation" then
updateAnimations()
end
end)
end
return
end
bumpImageUpdateToken()
rebuildAnimationNormalCache()
local currentPageAnimations = {}
local animationTable = {}
local equippedAnimations = {}
local categories = getCategoryStats()
local accumulatedPages = 0
local currentCat = nil
for _, cat in ipairs(categories) do
if State.currentPage <= accumulatedPages + cat.pages then
local adjustedPage = State.currentPage - accumulatedPages
currentPageAnimations = getListSlice(cat.list, adjustedPage, cat.hasRandom)
currentCat = cat
break
end
accumulatedPages = accumulatedPages + cat.pages
end
local randomActive = isRandomSlotActive()
if randomActive then
local randomFallback = currentPageAnimations[1] or (State.filteredAnimations and State.filteredAnimations[1])
if randomFallback then
animationTable["Random Animation"] = {randomFallback.id}
table.insert(equippedAnimations, "Random Animation")
end
end
State.animImageRetry = 0
for _, animation in pairs(currentPageAnimations) do
local animationName = animation.name
local animationId = animation.id
animationTable[animationName] = {animationId}
table.insert(equippedAnimations, animationName)
end
humanoidDescription:SetEmotes(animationTable)
humanoidDescription:SetEquippedEmotes(equippedAnimations)
updateAnimationImages(currentPageAnimations, randomActive)
if State.favoriteEnabled then
setEmotesButtonsActiveForFavorites()
end
task.delay(0.2, function()
if State.favoriteEnabled then
setEmotesButtonsActiveForFavorites()
end
if State.favoriteEnabled then
updateAllFavoriteIcons()
end
end)
end
updateEmotes = function()
local character, humanoid = getCharacterAndHumanoid()
if not character or not humanoid then
return
end
if State.currentMode == "animation" then
updateAnimations()
return
end
bumpImageUpdateToken()
local token = State.imageUpdateToken
if State.animImageSpamConn then
State.animImageSpamConn:Disconnect()
State.animImageSpamConn = nil
State.animImageSpamMap = nil
State.animImageSpamTicks = nil
State.animImageSpamToken = State.animImageSpamToken + 1
end
local humanoidDescription = humanoid.HumanoidDescription
if not humanoidDescription then
return
end
local currentPageEmotes = {}
local emoteTable = {}
local equippedEmotes = {}
rebuildEmoteNormalCache()
local categories = getCategoryStats()
local accumulatedPages = 0
local currentCat = nil
for _, cat in ipairs(categories) do
if State.currentPage <= accumulatedPages + cat.pages then
local adjustedPage = State.currentPage - accumulatedPages
currentPageEmotes = getListSlice(cat.list, adjustedPage, cat.hasRandom)
currentCat = cat
break
end
accumulatedPages = accumulatedPages + cat.pages
end
local randomActive = isRandomSlotActive()
if randomActive then
local randomFallback = currentPageEmotes[1] or (State.filteredEmotes and State.filteredEmotes[1])
if randomFallback then
emoteTable["Random Emote"] = {randomFallback.id}
table.insert(equippedEmotes, "Random Emote")
end
end
for _, emote in pairs(currentPageEmotes) do
local emoteName = emote.name
local emoteId = emote.id
emoteTable[emoteName] = {emoteId}
table.insert(equippedEmotes, emoteName)
end
humanoidDescription:SetEmotes(emoteTable)
humanoidDescription:SetEquippedEmotes(equippedEmotes)
local newTargetImages = {}
if randomActive then
newTargetImages["1"] = RANDOM_SLOT_ICON
end
local startSlot = randomActive and 2 or 1
for i = 1, 12 do
if i >= startSlot then
local listIndex = randomActive and (i - 1) or i
local emoteData = currentPageEmotes[listIndex]
if emoteData and emoteData.id then
newTargetImages[tostring(i)] = "rbxthumb://type=Asset&id=" .. tostring(emoteData.id) .. "&w=420&h=420"
else
newTargetImages[tostring(i)] = ""
end
end
end
State.targetImages = newTargetImages
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if success and frontFrame then
for slotName, image in pairs(newTargetImages) do
local child = frontFrame:FindFirstChild(slotName)
if child and child:IsA("ImageLabel") then
child.Image = image
if slotName == "1" and randomActive then
child.ImageColor3 = RANDOM_SLOT_COLOR
else
child.ImageColor3 = Color3.new(1, 1, 1)
end
end
end
if State.favoriteEnabled then
setEmotesButtonsActiveForFavorites()
end
if randomActive then
applyRandomSlotVisual(frontFrame)
spamRandomSlotVisual(frontFrame, token)
else
resetRandomSlotColor(frontFrame)
end
end
task.delay(0.2, function()
if State.favoriteEnabled then
setEmotesButtonsActiveForFavorites()
end
if State.favoriteEnabled then
updateAllFavoriteIcons()
end
end)
end
calculateTotalPages = function()
rebuildEmoteNormalCache()
rebuildAnimationNormalCache()
local categories = getCategoryStats()
local total = 0
for _, cat in ipairs(categories) do
total = total + cat.pages
end
return math.max(total, 1)
end
function isGivenAnimation(animationHolder, animationId)
for _, animation in animationHolder:GetChildren() do
if animation:IsA("Animation") and urlToId(animation.AnimationId) == animationId then
return true
end
end
return false
end
function isDancing(character, animationTrack)
local animationId = urlToId(animationTrack.Animation.AnimationId)
for _, animationHolder in character.Animate:GetChildren() do
if animationHolder:IsA("StringValue") then
local sharesAnimationId = isGivenAnimation(animationHolder, animationId)
if sharesAnimationId then
return false
end
end
end
return true
end
function createGUIElements()
local exists, emotesWheel = checkEmotesMenuExists()
if not exists then
return false
end
if UI.CustomFrames then
for _, frame in pairs(UI.CustomFrames) do
if frame and frame.Parent then frame:Destroy() end
end
end
UI.CustomFrames = {}
if emotesWheel:FindFirstChild("Under") then
emotesWheel.Under:Destroy()
end
if emotesWheel:FindFirstChild("Top") then
emotesWheel.Top:Destroy()
end
if emotesWheel:FindFirstChild("EmoteWalkButton") then
emotesWheel.EmoteWalkButton:Destroy()
end
if emotesWheel:FindFirstChild("Favorite") then
emotesWheel.Favorite:Destroy()
end
if emotesWheel:FindFirstChild("SpeedEmote") then
emotesWheel.SpeedEmote:Destroy()
end
if emotesWheel:FindFirstChild("Changepage") then
emotesWheel.Changepage:Destroy()
end
if emotesWheel:FindFirstChild("SpeedBox") then
emotesWheel.SpeedBox:Destroy()
end
if emotesWheel:FindFirstChild("Reload") then
emotesWheel.Reload:Destroy()
end
UI.Under = Instance.new("Frame")
local UIListLayout = Instance.new("UIListLayout")
UI._1left = Instance.new("ImageButton")
UI._9right = Instance.new("ImageButton")
UI._4pages = Instance.new("TextLabel")
UI._3TextLabel = Instance.new("TextLabel")
UI._2Routenumber = Instance.new("TextBox")
UI.EmoteWalkButton = Instance.new("ImageButton")
local UICorner_Left = Instance.new("UICorner")
UICorner_Left.CornerRadius = UDim.new(0, 10)
UICorner_Left.Parent = UI._1left
local UICorner_Right = Instance.new("UICorner")
UICorner_Right.CornerRadius = UDim.new(0, 10)
UICorner_Right.Parent = UI._9right
local UICorner1 = Instance.new("UICorner")
UI.Top = Instance.new("Frame")
local UIListLayout_2 = Instance.new("UIListLayout")
local UICorner = Instance.new("UICorner")
UI.Search = Instance.new("TextBox")
UI.Favorite = Instance.new("ImageButton")
local UICorner2 = Instance.new("UICorner")
UI.SpeedBox = Instance.new("TextBox")
local UICorner_4 = Instance.new("UICorner")
UI.SpeedEmote = Instance.new("ImageButton")
local UICorner_2 = Instance.new("UICorner")
UI.Changepage = Instance.new("ImageButton")
local UICorner_5 = Instance.new("UICorner")
UI.Reload = Instance.new("ImageButton")
local UICorner_6 = Instance.new("UICorner")
UI.Under.Name = "Under"
UI.Under.Parent = emotesWheel
UI.Under.BackgroundTransparency = 1.000
UI.Under.BorderSizePixel = 0
UI.Under.Position = UDim2.new(0.129999995, 0, 1, 0)
UI.Under.Size = UDim2.new(0.737500012, 0, 0.132499993, 0)
UIListLayout.Parent = UI.Under
UIListLayout.FillDirection = Enum.FillDirection.Horizontal
UIListLayout.VerticalAlignment = Enum.VerticalAlignment.Center
UI._1left.Name = "1left"
UI._1left.Parent = UI.Under
UI._1left.BackgroundTransparency = 1.000
UI._1left.BorderSizePixel = 0
UI._1left.Size = UDim2.new(0.169491529, 0, 0.94339627, 0)
UI._1left.Image = "rbxassetid://93111945058621"
UI._1left.ImageColor3 = Color3.fromRGB(0, 0, 0)
UI._1left.ImageTransparency = 0.400
UI._9right.Name = "9right"
UI._9right.Parent = UI.Under
UI._9right.BackgroundTransparency = 1.000
UI._9right.BorderSizePixel = 0
UI._9right.Size = UDim2.new(0.169491529, 0, 0.94339627, 0)
UI._9right.Image = "rbxassetid://107938916240738"
UI._9right.ImageColor3 = Color3.fromRGB(0, 0, 0)
UI._9right.ImageTransparency = 0.400
UI._4pages.Name = "4pages"
UI._4pages.Parent = UI.Under
UI._4pages.BackgroundTransparency = 1.000
UI._4pages.BorderSizePixel = 0
UI._4pages.Size = UDim2.new(0.159322038, 0, 0.811320841, 0)
UI._4pages.Font = Enum.Font.SourceSansBold
UI._4pages.Text = "1"
UI._4pages.TextColor3 = Color3.fromRGB(0, 0, 0)
UI._4pages.TextScaled = true
UI._4pages.TextSize = 14.000
UI._4pages.TextTransparency = 0.400
UI._4pages.TextWrapped = true
UI._3TextLabel.Name = "3TextLabel"
UI._3TextLabel.Parent = UI.Under
UI._3TextLabel.BackgroundTransparency = 1.000
UI._3TextLabel.BorderSizePixel = 0
UI._3TextLabel.Size = UDim2.new(0.338983059, 0, 0.94339627, 0)
UI._3TextLabel.Font = Enum.Font.SourceSansBold
UI._3TextLabel.Text = " ------ "
UI._3TextLabel.TextColor3 = Color3.fromRGB(0, 0, 0)
UI._3TextLabel.TextScaled = true
UI._3TextLabel.TextSize = 14.000
UI._3TextLabel.TextTransparency = 0.400
UI._3TextLabel.TextWrapped = true
UI._2Routenumber.Name = "2Route-number"
UI._2Routenumber.Parent = UI.Under
UI._2Routenumber.Active = true
UI._2Routenumber.BackgroundTransparency = 1.000
UI._2Routenumber.BorderSizePixel = 0
UI._2Routenumber.Size = UDim2.new(0.159322038, 0, 0.811320841, 0)
UI._2Routenumber.Font = Enum.Font.SourceSansBold
UI._2Routenumber.PlaceholderColor3 = Color3.fromRGB(0, 0, 0)
UI._2Routenumber.Text = "1"
UI._2Routenumber.TextColor3 = Color3.fromRGB(0, 0, 0)
UI._2Routenumber.TextScaled = true
UI._2Routenumber.TextSize = 14.000
UI._2Routenumber.TextTransparency = 0.400
UI._2Routenumber.TextWrapped = true
UI.Top.Name = "Top"
UI.Top.Parent = emotesWheel
UI.Top.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
UI.Top.BackgroundTransparency = 0.400
UI.Top.BorderSizePixel = 0
UI.Top.Position = UDim2.new(0.127499998, 0, -0.109999999, 0)
UI.Top.Size = UDim2.new(0.737500012, 0, 0.0949999914, 0)
UIListLayout_2.Parent = UI.Top
UIListLayout_2.FillDirection = Enum.FillDirection.Horizontal
UIListLayout_2.HorizontalAlignment = Enum.HorizontalAlignment.Center
UIListLayout_2.SortOrder = Enum.SortOrder.LayoutOrder
UIListLayout_2.VerticalAlignment = Enum.VerticalAlignment.Center
UICorner.CornerRadius = UDim.new(0, 20)
UICorner.Parent = UI.Top
UI.Search.Name = "Search"
UI.Search.Parent = UI.Top
UI.Search.BackgroundTransparency = 1.000
UI.Search.Size = UDim2.new(0.864406765, 0, 0.81578958, 0)
UI.Search.Font = Enum.Font.SourceSansBold
UI.Search.PlaceholderText = "Search/ID"
UI.Search.Text = ""
UI.Search.TextColor3 = Color3.fromRGB(255, 255, 255)
UI.Search.TextScaled = true
UI.Search.TextSize = 14.000
UI.Search.TextWrapped = true
UI.EmoteWalkButton.Name = "EmoteWalkButton"
UI.EmoteWalkButton.Parent = emotesWheel
UI.EmoteWalkButton.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
UI.EmoteWalkButton.BackgroundTransparency = 0.400
UI.EmoteWalkButton.BorderSizePixel = 0
UI.EmoteWalkButton.Position = UDim2.new(0.889999986, 0, -0.107500002, 0)
UI.EmoteWalkButton.Size = UDim2.new(0.0874999985, 0, 0.0874999985, 0)
UI.EmoteWalkButton.Image = State.defaultButtonImage
UICorner1.CornerRadius = UDim.new(0, 10)
UICorner1.Parent = UI.EmoteWalkButton
UI.Favorite.Name = "Favorite"
UI.Favorite.Parent = emotesWheel
UI.Favorite.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
UI.Favorite.BackgroundTransparency = 0.400
UI.Favorite.BorderSizePixel = 0
UI.Favorite.Position = UDim2.new(0.0189999994, 0, -0.108000003, 0)
UI.Favorite.Size = UDim2.new(0.0874999985, 0, 0.0874999985, 0)
UI.Favorite.Image = "rbxassetid://124025954365505"
UICorner2.CornerRadius = UDim.new(0, 10)
UICorner2.Parent = UI.Favorite
UI.SpeedBox.Name = "SpeedBox"
UI.SpeedBox.Parent = emotesWheel
UI.SpeedBox.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
UI.SpeedBox.BackgroundTransparency = 0.400
UI.SpeedBox.BorderSizePixel = 0
UI.SpeedBox.Position = UDim2.new(0.0189999398, 0, -0.000499992399, 0)
UI.SpeedBox.Size = UDim2.new(0.0874999985, 0, 0.0874999985, 0)
UI.SpeedBox.Visible = false
UI.SpeedBox.Font = Enum.Font.SourceSansBold
UI.SpeedBox.PlaceholderColor3 = Color3.fromRGB(178, 178, 178)
UI.SpeedBox.Text = "1"
UI.SpeedBox.TextColor3 = Color3.fromRGB(255, 255, 255)
UI.SpeedBox.TextScaled = true
UI.SpeedBox.TextWrapped = true
UI.SpeedBox:GetPropertyChangedSignal("Text"):Connect(function()
UI.SpeedBox.Text = UI.SpeedBox.Text:gsub("[^%d.]", "")
end)
UI.SpeedBox.ZIndex = 2
UICorner_4.CornerRadius = UDim.new(0, 10)
UICorner_4.Parent = UI.SpeedBox
UI.SpeedEmote.Name = "SpeedEmote"
UI.SpeedEmote.Parent = emotesWheel
UI.SpeedEmote.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
UI.SpeedEmote.BackgroundTransparency = 0.400
UI.SpeedEmote.BorderSizePixel = 0
UI.SpeedEmote.Position = UDim2.new(0.888999999, 0, -0, 0)
UI.SpeedEmote.Size = UDim2.new(0.0874999985, 0, 0.0874999985, 0)
UI.SpeedEmote.Image = "rbxassetid://116056570415896"
UI.SpeedEmote.ZIndex = 2
UICorner_2.CornerRadius = UDim.new(0, 10)
UICorner_2.Parent = UI.SpeedEmote
UI.Changepage.Name = "Changepage"
UI.Changepage.Parent = emotesWheel
UI.Changepage.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
UI.Changepage.BackgroundTransparency = 0.400
UI.Changepage.BorderColor3 = Color3.fromRGB(0, 0, 0)
UI.Changepage.BorderSizePixel = 0
UI.Changepage.Position = UDim2.new(0.019, 0,1.021, 0)
UI.Changepage.Size = UDim2.new(0.087, 0,0.087, 0)
UI.Changepage.ZIndex = 3
UI.Changepage.Image = "rbxassetid://13285615740"
UICorner_5.CornerRadius = UDim.new(0, 10)
UICorner_5.Parent = UI.Changepage
UI.Reload.Name = "Reload"
UI.Reload.Parent = emotesWheel
UI.Reload.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
UI.Reload.BackgroundTransparency = 0.400
UI.Reload.BorderSizePixel = 0
UI.Reload.Position = UDim2.new(0.888999999, 0, 1.02100003, 0)
UI.Reload.Size = UDim2.new(0.0869999975, 0, 0.0869999975, 0)
UI.Reload.ZIndex = 3
UI.Reload.Image = "rbxassetid://127493377027615"
UICorner_6.CornerRadius = UDim.new(0, 10)
UICorner_6.Parent = UI.Reload
local function spawnCustomFrame(name, zIndex)
local cf = Instance.new("Frame")
cf.Name = name
cf.Parent = emotesWheel
cf.BackgroundColor3 = Color3.fromRGB(0,0,0)
cf.BackgroundTransparency = 0.4
cf.ZIndex = zIndex or 3
cf.BorderSizePixel = 0
cf.Active = true
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 10)
corner.Parent = cf
if not UI.CustomFrames then UI.CustomFrames = {} end
UI.CustomFrames[name] = cf
return cf
end
local function recordDefaults()
local allMovable = getMovableElements()
for name, el in pairs(allMovable) do
HUD.DefaultPositions[name] = el.Position
HUD.DefaultSizes[name] = el.Size
if el:IsA("TextLabel") or el:IsA("TextBox") then
HUD.DefaultTexts[name] = el.Text
if el:IsA("TextBox") then
HUD.DefaultPlaceholders[name] = el.PlaceholderText
end
end
end
end
if Config.CustomFrames then
for name, data in pairs(Config.CustomFrames) do
spawnCustomFrame(name, data.ZIndex or 3)
end
end
recordDefaults()
loadSpeedEmoteConfig()
connectEvents()
State.isGUICreated = true
ApplyTheme(themes[currentThemeName] or themes.Default)
updateGUIColors()
ApplyUIVisibility()
if ApplyFreezeButtonVisual then ApplyFreezeButtonVisual() end
if applySavedPositions then applySavedPositions() end
if updateHUDLayouts then updateHUDLayouts() end
return true
end
updatePageDisplay = function()
if UI._4pages and UI._2Routenumber then
UI._4pages.Text = tostring(State.totalPages)
UI._2Routenumber.Text = tostring(State.currentPage)
end
if State.currentMode == "animation" then
Config.AnimationPage = State.currentPage
else
Config.EmotePage = State.currentPage
end
SaveConfig()
end
toggleFavorite = function(emoteId, emoteName)
local found = false
local index = 0
for i, fav in pairs(State.favoriteEmotes) do
if tostring(fav.id) == tostring(emoteId) then
found = true
index = i
break
end
end
if found then
table.remove(State.favoriteEmotes, index)
getgenv().Notify({
Title = '7yd7 | Favorite System',
Content = '🗑️ Removed "' .. emoteName .. '" from favorites',
Duration = 3
})
else
table.insert(State.favoriteEmotes, {
id = emoteId,
name = emoteName .. " - ⭐"
})
getgenv().Notify({
Title = '7yd7 | Favorite System',
Content = '✅ Added "' .. emoteName .. '" to favorites',
Duration = 3
})
end
State.EmotePages.Sets[State.currentEmotePageName] = DeepCopy(State.favoriteEmotes)
State.SaveEmotePages(State.EmotePages)
State.favoriteSetVersion = State.favoriteSetVersion + 1
State.totalPages = calculateTotalPages()
updatePageDisplay()
updateEmotes()
updateAllFavoriteIcons()
end
toggleFavoriteAnimation = function(animationData)
local found = false
local index = 0
for i, fav in pairs(State.favoriteAnimations) do
if fav.id == animationData.id then
found = true
index = i
break
end
end
if found then
table.remove(State.favoriteAnimations, index)
getgenv().Notify({
Title = '7yd7 | Favorite System',
Content = '🗑️ Removed "' .. animationData.name .. '" from favorites',
Duration = 3
})
else
table.insert(State.favoriteAnimations, {
id = animationData.id,
name = animationData.name .. " - ⭐",
bundledItems = animationData.bundledItems,
isCustomSet = IsCustomSetData(animationData),
customSetName = IsCustomSetData(animationData) and (type(animationData.name) == "string" and animationData.name:gsub("%s*%-.*$", "") or animationData.name) or nil
})
getgenv().Notify({
Title = '7yd7 | Favorite System',
Content = '✅ Added "' .. animationData.name .. '" to favorites',
Duration = 3
})
end
State.favoriteSetVersion = State.favoriteSetVersion + 1
State.AnimationPages.Sets[State.currentAnimationPageName] = DeepCopy(State.favoriteAnimations)
State.SaveAnimationPages(State.AnimationPages)
State.totalPages = calculateTotalPages()
updatePageDisplay()
updateAnimations()
updateAllFavoriteIcons()
end
function setupEmoteClickDetection()
if State.isMonitoringClicks then
return
end
State.emoteMonitorToken = State.emoteMonitorToken + 1
local token = State.emoteMonitorToken
local function monitorEmotes()
while State.favoriteEnabled and State.currentMode == "emote" and State.emoteMonitorToken == token do
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if success and frontFrame then
for _, connection in pairs(State.emoteClickConnections) do
if connection then
connection:Disconnect()
end
end
State.emoteClickConnections = {}
local randomActive = isRandomSlotActive()
for _, child in pairs(frontFrame:GetChildren()) do
if child:IsA("ImageLabel") and child.Image ~= "" and (not randomActive or child.Name ~= "1") then
local imageUrl = child.Image
local assetId = extractAssetId(imageUrl)
if assetId then
local isFavorite = isInFavorites(assetId)
updateFavoriteIcon(child, assetId, isFavorite)
end
end
end
applyEmotesButtonsActiveState()
end
task.wait(0.1)
end
end
if State.favoriteEnabled then
State.isMonitoringClicks = true
task.spawn(monitorEmotes)
end
end
applyAnimation = function(animationData)
local player = game.Players.LocalPlayer
local character = player.Character or player.CharacterAdded:Wait()
local humanoid = character:FindFirstChild("Humanoid")
local animate = character:FindFirstChild("Animate")
if not animate or not humanoid then
getgenv().Notify({
Title = '7yd7 | Animation Error',
Content = '❌ Animate or Humanoid not found',
Duration = 3
})
return
end
local bundleId = animationData.id
local bundledItems = animationData.bundledItems
getgenv().lastPlayedAnimation = animationData
Config.LastPlayedAnimationData = animationData
task.spawn(SaveConfig)
if not bundledItems and not animationData.isCustomSet then
getgenv().Notify({
Title = '7yd7 | Animation Error',
Content = '??? No bundled items found',
Duration = 3
})
return
end
if animationData.isCustomSet and not bundledItems then
bundledItems = {"Custom-Animation"}
end
for _, track in pairs(humanoid:GetPlayingAnimationTracks()) do
track:Stop()
end
local cacheKey = tostring(bundleId)
local mappings = State.AnimationCache[cacheKey]
if animationData.isCustomSet then
mappings = buildCustomSetMappings(GetCustomSetName(animationData) or animationData.name)
if #mappings > 0 then
State.AnimationCache[cacheKey] = mappings
task.spawn(saveAnimationCache)
end
elseif not mappings then
mappings = resolveAnimationMappings(bundledItems)
if #mappings > 0 then
State.AnimationCache[cacheKey] = mappings
task.spawn(saveAnimationCache)
end
end
if #mappings == 0 then return end
local sorted = {}
for _, m in pairs(mappings) do
if m.category:lower() == "idle" then
table.insert(sorted, 1, m)
else
table.insert(sorted, m)
end
end
for _, m in pairs(sorted) do
local categoryFolder = animate:FindFirstChild(m.category)
if categoryFolder then
for _, animObj in ipairs(categoryFolder:GetChildren()) do
if animObj:IsA("Animation") then
if animationData.isCustomSet then
if animObj.Name == m.name then
animObj.AnimationId = m.animationId
end
else
animObj.AnimationId = m.animationId
end
end
end
end
end
if humanoid.MoveDirection.Magnitude == 0 then
animate.Disabled = true
animate.Disabled = false
end
end
function playAnimationPreview(animationData)
local _, humanoid = getCharacterAndHumanoid()
if not humanoid then return false end
local animator = humanoid:FindFirstChild("Animator")
if not animator then return false end
local bundledItems = animationData and animationData.bundledItems
if not bundledItems then return false end
local bundleId = animationData.id
local cacheKey = tostring(bundleId)
local mappings = State.AnimationCache[cacheKey]
if not mappings then
mappings = resolveAnimationMappings(bundledItems)
if #mappings > 0 then
State.AnimationCache[cacheKey] = mappings
task.spawn(saveAnimationCache)
end
end
if #mappings == 0 then return false end
local m = mappings[1]
local animation = Instance.new("Animation")
animation.AnimationId = m.animationId
local ok, track = pcall(function()
return animator:LoadAnimation(animation)
end)
if ok and track then
track.Priority = Enum.AnimationPriority.Action
track.Looped = true
if State.speedEmoteEnabled or State.emotesWalkEnabled then
track:Play()
end
State.currentEmoteTrack = track
if State.speedEmoteEnabled then
local speedVal = tonumber(UI.SpeedBox.Text) or Config.EmoteSpeed or 1
track:AdjustSpeed(speedVal)
end
return true
end
return false
end
handleSectorAction = function(index)
if tick() - State.lastActionTick < 0.25 then return end
State.lastActionTick = tick()
if State.customAnimationEditorActive and (not State.customAnimationEditingKey or not State.customAnimationEditingName or not (State.CustomAnimOverlay and State.CustomAnimOverlay.Parent)) then
if State.exitCustomAnimationEditor then
State.exitCustomAnimationEditor()
else
State.customAnimationEditorActive = false
end
end
local randomActive = isRandomSlotActive()
if index == 1 and randomActive then
local itemData = pickRandomItemForMode()
if not itemData then
getgenv().Notify({
Title = '7yd7 | Random',
Content = '? No valid random item found',
Duration = 3
})
return
end
State.lastRadialActionTime = tick()
if State.customAnimationEditorActive then
local animIdToSave = itemData.id
local cat = State.customAnimationEditingKey
local name = State.customAnimationEditingName
if State.CustomAnimations.Sets[State.currentCustomAnimationName] and cat and name then
if State.currentMode == "emote" or (State.currentMode == "animation" and not itemData.bundledItems) then
local resolved = resolveEmoteToAnimationId(itemData.id)
if resolved then animIdToSave = resolved end
end
if not State.CustomAnimations.Sets[State.currentCustomAnimationName][cat] then
State.CustomAnimations.Sets[State.currentCustomAnimationName][cat] = {}
end
State.CustomAnimations.Sets[State.currentCustomAnimationName][cat][name] = animIdToSave
State.SaveCustomAnimations(State.CustomAnimations)
getgenv().Notify({ Title = "7yd7 | Saved", Content = "✅ Saved " .. name, Duration = 3 })
if State.RefreshCustomAnimUI then State.RefreshCustomAnimUI() end
if refreshCustomAnimationState then refreshCustomAnimationState(true) end
State.exitCustomAnimationEditor()
end
return
end
if State.favoriteEnabled then
if State.currentMode == "animation" then
if not isInFavorites(itemData.id) then
toggleFavoriteAnimation(itemData)
end
else
if not isInFavorites(itemData.id) then
toggleFavorite(itemData.id, itemData.name)
end
end
return
end
if State.currentMode == "animation" then
if stopCurrentEmote then stopCurrentEmote() end
applyAnimation(itemData)
State.lastRandomAnimationId = itemData.id
if not State.favoriteEnabled then
pcall(function()
game:GetService("GuiService"):SetEmotesMenuOpen(false)
end)
pcall(function()
game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Visible = false
end)
end
else
local _, hum = getCharacterAndHumanoid()
if hum then
pcall(function()
game:GetService("GuiService"):SetEmotesMenuOpen(false)
end)
pcall(function()
game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Visible = false
end)
playRandomEmote(hum, itemData.id)
State.lastRandomEmoteId = itemData.id
end
end
return
end
if State.currentMode == "animation" then
rebuildAnimationNormalCache()
else
rebuildEmoteNormalCache()
end
local function getEmoteAtIndex(idx)
local categories = getCategoryStats()
local accumulatedPages = 0
for _, cat in ipairs(categories) do
if State.currentPage <= accumulatedPages + cat.pages then
local adjustedPage = State.currentPage - accumulatedPages
local pageItems = getListSlice(cat.list, adjustedPage, cat.hasRandom)
return pageItems[idx]
end
accumulatedPages = accumulatedPages + cat.pages
end
return nil
end
local slotOffset = randomActive and 1 or 0
local itemData = getEmoteAtIndex(index - slotOffset)
if not itemData then return end
State.lastRadialActionTime = tick()
if State.customAnimationEditorActive then
local animIdToSave = itemData.id
local cat = State.customAnimationEditingKey
local name = State.customAnimationEditingName
if State.currentMode == "emote" or (State.currentMode == "animation" and not itemData.bundledItems) then
local resolved = resolveEmoteToAnimationId(itemData.id)
if resolved then animIdToSave = resolved end
end
if State.currentMode == "animation" and itemData.bundledItems then
local resolved = resolveAnimationMappings(itemData.bundledItems)
if resolved and #resolved > 0 then
local match
for _, m in ipairs(resolved) do
if m.category:lower() == cat:lower() and m.name:lower() == name:lower() then
match = m
break
end
end
if not match then
for _, m in ipairs(resolved) do
if m.category:lower() == cat:lower() then
match = m
break
end
end
end
if match then
local extractedId = tonumber(urlToId(match.animationId))
if extractedId then
animIdToSave = extractedId
end
end
if animIdToSave == itemData.id and resolved[1] then
animIdToSave = tonumber(urlToId(resolved[1].animationId)) or itemData.id
end
end
end
if State.CustomAnimations.Sets[State.currentCustomAnimationName] and cat and name then
if not State.CustomAnimations.Sets[State.currentCustomAnimationName][cat] then
State.CustomAnimations.Sets[State.currentCustomAnimationName][cat] = {}
end
State.CustomAnimations.Sets[State.currentCustomAnimationName][cat][name] = animIdToSave
State.SaveCustomAnimations(State.CustomAnimations)
getgenv().Notify({ Title = "7yd7 | Saved", Content = "✅ Saved " .. name, Duration = 3 })
if State.RefreshCustomAnimUI then State.RefreshCustomAnimUI() end
if refreshCustomAnimationState then refreshCustomAnimationState(true) end
State.exitCustomAnimationEditor()
end
return
end
if State.favoriteEnabled then
if State.currentMode == "animation" then
toggleFavoriteAnimation(itemData)
else
toggleFavorite(itemData.id, itemData.name)
end
else
if State.currentMode == "animation" then
applyAnimation(itemData)
pcall(function()
game:GetService("GuiService"):SetEmotesMenuOpen(false)
end)
pcall(function()
game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Visible = false
end)
else
local _, hum = getCharacterAndHumanoid()
if hum then
if playRandomEmote then
playRandomEmote(hum, itemData.id)
elseif playEmote then
playEmote(hum, itemData.id)
end
end
end
end
end
function clearAnimationSlotImages()
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if not success or not frontFrame then
return
end
for i = 1, State.itemsPerPage do
local child = frontFrame:FindFirstChild(tostring(i))
if child and child:IsA("ImageLabel") then
local idValue = child:FindFirstChild("AnimationID")
if idValue then
idValue:Destroy()
end
if child.Image and child.Image:find("rbxthumb://type=BundleThumbnail") then
child.Image = ""
end
end
end
end
function monitorAnimations(token)
while State.currentMode == "animation" and State.animationMonitorToken == token do
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if success and frontFrame then
for _, connection in pairs(State.emoteClickConnections) do
if connection then
connection:Disconnect()
end
end
State.emoteClickConnections = {}
local favoritesToUse = _G.filteredFavoritesAnimationsForDisplay or State.favoriteAnimations
local hasFavorites = #favoritesToUse > 0
local favoritePagesCount = hasFavorites and calcPagesForList(#favoritesToUse, true) or 0
local isInFavoritesPages = State.currentPage <= favoritePagesCount
local currentPageAnimations = {}
if isInFavoritesPages and hasFavorites then
currentPageAnimations = getListSlice(favoritesToUse, State.currentPage, true)
else
local normalAnimations = {}
for _, animation in pairs(State.filteredAnimations) do
if not isInFavorites(animation.id) then
table.insert(normalAnimations, animation)
end
end
local adjustedPage = State.currentPage - favoritePagesCount
local isFirstNormalList = (favoritePagesCount == 0)
currentPageAnimations = getListSlice(normalAnimations, adjustedPage, isFirstNormalList)
end
local randomActive = isRandomSlotActive()
local buttonIndex = 1
for _, child in pairs(frontFrame:GetChildren()) do
if child:IsA("ImageLabel") and (not randomActive or child.Name ~= "1") then
if buttonIndex <= #currentPageAnimations then
local animationData = currentPageAnimations[buttonIndex]
if State.favoriteEnabled then
local isFavorite = isInFavorites(animationData.id)
updateFavoriteIcon(child, animationData.id, isFavorite)
else
local favoriteIcon = child:FindFirstChild("FavoriteIcon")
if favoriteIcon then
favoriteIcon:Destroy()
end
end
buttonIndex = buttonIndex + 1
else
local favoriteIcon = child:FindFirstChild("FavoriteIcon")
if favoriteIcon then
favoriteIcon:Destroy()
end
end
end
end
end
task.wait(0.1)
end
end
function stopEmoteClickDetection()
State.isMonitoringClicks = false
State.emoteMonitorToken = State.emoteMonitorToken + 1
State.animationMonitorToken = State.animationMonitorToken + 1
for _, connection in pairs(State.emoteClickConnections) do
if connection then
connection:Disconnect()
end
end
State.emoteClickConnections = {}
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if success and frontFrame then
for _, child in pairs(frontFrame:GetChildren()) do
if child:IsA("ImageLabel") then
local clickDetector = child:FindFirstChild("ClickDetector")
if clickDetector then
clickDetector:Destroy()
end
local favoriteIcon = child:FindFirstChild("FavoriteIcon")
if favoriteIcon then
favoriteIcon:Destroy()
end
end
end
applyEmotesButtonsActiveState()
end
end
function fetchAllEmotes()
if State.isLoading then
return
end
State.isLoading = true
State.emotesData = {}
State.totalEmotesLoaded = 0
local success, result = pcall(function()
local jsonContent = game:HttpGet("https://raw.githubusercontent.com/7yd7/sniper-Emote/refs/heads/test/EmoteSniper.json")
if jsonContent and jsonContent ~= "" then
local data = HttpService:JSONDecode(jsonContent)
return data.data or {}
else
return nil
end
end)
if success and result then
for _, item in pairs(result) do
local emoteData = {
id = tonumber(item.id),
name = item.name or ("Emote_" .. (item.id or "Unknown"))
}
if emoteData.id and emoteData.id > 0 then
table.insert(State.emotesData, emoteData)
State.totalEmotesLoaded = State.totalEmotesLoaded + 1
end
end
else
State.emotesData = {
{id = 3360686498, name = "Stadium"},
{id = 3360692915, name = "Tilt"},
{id = 3576968026, name = "Shrug"},
{id = 3360689775, name = "Salute"}
}
State.totalEmotesLoaded = #State.emotesData
end
State.originalEmotesData = State.emotesData
State.filteredEmotes = State.emotesData
State.emoteCacheVersion = State.emoteCacheVersion + 1
State.totalPages = calculateTotalPages()
State.currentPage = 1
updatePageDisplay()
updateEmotes()
getgenv().Notify({
Title = '7yd7 | Emote',
Content = "🎉 Loaded Successfully! Total Emotes: " .. State.totalEmotesLoaded,
Duration = 5
})
State.isLoading = false
end
function fetchAllAnimations()
if State.isLoading then
return
end
State.isLoading = true
State.animationsData = {}
local success, result = pcall(function()
local jsonContent = game:HttpGet("https://raw.githubusercontent.com/7yd7/sniper-Emote/refs/heads/test/AnimationSniper.json")
if jsonContent and jsonContent ~= "" then
local data = HttpService:JSONDecode(jsonContent)
return data.data or {}
else
return nil
end
end)
if success and result then
for _, item in pairs(result) do
local animationData = {
id = tonumber(item.id),
name = item.name or ("Animation_" .. (item.id or "Unknown")),
bundledItems = item.bundledItems
}
if animationData.id and animationData.id > 0 then
table.insert(State.animationsData, animationData)
end
end
end
if State.CustomAnimations and State.CustomAnimations.Order then
for idx, customSetName in ipairs(State.CustomAnimations.Order) do
if customSetName ~= "Default" and State.CustomAnimations.Sets[customSetName] then
local fakeId = -1000 - idx
local customSetData = State.CustomAnimations.Sets[customSetName]
local mappings = {}
for cat, anims in pairs(customSetData) do
if cat ~= "__meta" then
for name, id in pairs(anims) do
if tostring(id) ~= "0" then
table.insert(mappings, {category = cat, name = name, animationId = "rbxassetid://" .. id})
end
end
end
end
State.AnimationCache[tostring(fakeId)] = mappings
local customAnimationData = {
id = fakeId,
name = customSetName,
bundledItems = {"Custom-Animation"},
isCustomSet = true
}
table.insert(State.animationsData, 1, customAnimationData)
end
end
end
State.originalAnimationsData = State.animationsData
State.filteredAnimations = State.animationsData
State.animationCacheVersion = State.animationCacheVersion + 1
State.isLoading = false
end
local function smartSearchMatch(name, searchTerm)
if not searchTerm or searchTerm == "" then return true end
name = name:lower()
searchTerm = searchTerm:lower()
for word in searchTerm:gmatch("%S+") do
if not name:find(word, 1, true) then
return false
end
end
return true
end
function searchEmotes(searchTerm)
if State.isLoading then
getgenv().Notify({
Title = '7yd7 | Emote',
Content = '⚠️ Loading please wait...',
Duration = 5
})
return
end
searchTerm = searchTerm:lower()
if searchTerm == "" then
State.filteredEmotes = State.originalEmotesData
State.emoteCacheVersion = State.emoteCacheVersion + 1
if _G.originalFavoritesBackup then
_G.originalFavoritesBackup = nil
end
_G.filteredFavoritesForDisplay = nil
else
local isIdSearch = searchTerm:match("^%d+$")
local newFilteredList = {}
if isIdSearch then
for _, emote in pairs(State.originalEmotesData) do
if tostring(emote.id) == searchTerm then
table.insert(newFilteredList, emote)
end
end
else
for _, emote in pairs(State.originalEmotesData) do
if smartSearchMatch(emote.name, searchTerm) then
table.insert(newFilteredList, emote)
end
end
end
State.filteredEmotes = newFilteredList
State.emoteCacheVersion = State.emoteCacheVersion + 1
if not isIdSearch then
if not _G.originalFavoritesBackup then
_G.originalFavoritesBackup = {}
for i, favorite in pairs(State.favoriteEmotes) do
_G.originalFavoritesBackup[i] = {
id = favorite.id,
name = favorite.name
}
end
end
_G.filteredFavoritesForDisplay = {}
for _, favorite in pairs(State.favoriteEmotes) do
if smartSearchMatch(favorite.name, searchTerm) then
table.insert(_G.filteredFavoritesForDisplay, favorite)
end
end
end
applySearchSlot1Image()
end
State.totalPages = calculateTotalPages()
State.currentPage = 1
updatePageDisplay()
updateEmotes()
end
function searchAnimations(searchTerm)
if State.isLoading then
getgenv().Notify({
Title = '7yd7 | Animation',
Content = '⚠️ Loading please wait...',
Duration = 5
})
return
end
searchTerm = searchTerm:lower()
if searchTerm == "" then
State.filteredAnimations = State.originalAnimationsData
State.animationCacheVersion = State.animationCacheVersion + 1
if _G.originalAnimationFavoritesBackup then
_G.originalAnimationFavoritesBackup = nil
end
_G.filteredFavoritesAnimationsForDisplay = nil
else
local isIdSearch = searchTerm:match("^%d+$")
local newFilteredList = {}
if isIdSearch then
for _, animation in pairs(State.originalAnimationsData) do
if tostring(animation.id) == searchTerm then
table.insert(newFilteredList, animation)
end
end
else
for _, animation in pairs(State.originalAnimationsData) do
if smartSearchMatch(animation.name, searchTerm) then
table.insert(newFilteredList, animation)
end
end
end
State.filteredAnimations = newFilteredList
State.animationCacheVersion = State.animationCacheVersion + 1
if not isIdSearch then
if not _G.originalAnimationFavoritesBackup then
_G.originalAnimationFavoritesBackup = {}
for i, favorite in pairs(State.favoriteAnimations) do
_G.originalAnimationFavoritesBackup[i] = {
id = favorite.id,
name = favorite.name,
bundledItems = favorite.bundledItems
}
end
end
_G.filteredFavoritesAnimationsForDisplay = {}
for _, favorite in pairs(State.favoriteAnimations) do
if smartSearchMatch(favorite.name, searchTerm) then
table.insert(_G.filteredFavoritesAnimationsForDisplay, favorite)
end
end
end
applySearchSlot1Image()
end
State.totalPages = calculateTotalPages()
State.currentPage = 1
updatePageDisplay()
updateAnimations()
end
findCustomAnimationDataByName = function(setName)
if not setName or setName == "Default" then
return nil
end
for _, animationData in ipairs(State.originalAnimationsData or {}) do
if animationData.isCustomSet and animationData.name == setName then
return animationData
end
end
for _, animationData in ipairs(State.animationsData or {}) do
if animationData.isCustomSet and animationData.name == setName then
return animationData
end
end
return nil
end
refreshCustomAnimationState = function(applySelectedSet)
local activeSearch = State.animationSearchTerm or ""
local previousPage = State.currentPage
fetchAllAnimations()
if activeSearch ~= "" then
searchAnimations(activeSearch)
else
State.filteredAnimations = State.originalAnimationsData
State.animationCacheVersion = State.animationCacheVersion + 1
State.totalPages = calculateTotalPages()
local maxPage = math.max(State.totalPages, 1)
if previousPage < 1 then
State.currentPage = 1
elseif previousPage > maxPage then
State.currentPage = maxPage
else
State.currentPage = previousPage
end
updatePageDisplay()
if State.currentMode == "animation" then
updateAnimations()
end
end
if applySelectedSet and State.currentCustomAnimationName ~= "Default" then
local selectedAnimationData = findCustomAnimationDataByName(State.currentCustomAnimationName)
if selectedAnimationData then
pcall(function()
applyAnimation(selectedAnimationData)
end)
end
end
end
function goToPage(pageNumber)
bumpImageUpdateToken()
if pageNumber < 1 then
State.currentPage = 1
elseif pageNumber > State.totalPages then
State.currentPage = State.totalPages
else
State.currentPage = pageNumber
end
updatePageDisplay()
updateEmotes()
end
function previousPage()
bumpImageUpdateToken()
if State.currentPage <= 1 then
State.currentPage = State.totalPages
else
State.currentPage = State.currentPage - 1
end
updatePageDisplay()
updateEmotes()
end
function nextPage()
bumpImageUpdateToken()
if State.currentPage >= State.totalPages then
State.currentPage = 1
else
State.currentPage = State.currentPage + 1
end
updatePageDisplay()
updateEmotes()
end
function stopCurrentEmote()
if State.currentEmoteTrack then
State.currentEmoteTrack:Stop()
State.currentEmoteTrack = nil
end
end
playEmote = function(humanoid, emoteId)
stopCurrentEmote()
stopEmotes()
local animation = Instance.new("Animation")
animation.AnimationId = "rbxassetid://" .. emoteId
local success, animTrack = pcall(function()
return humanoid.Animator:LoadAnimation(animation)
end)
if success and animTrack then
State.currentEmoteTrack = animTrack
State.currentEmoteTrack.Priority = Enum.AnimationPriority.Action
State.currentEmoteTrack.Looped = true
task.wait(0.1)
if State.speedEmoteEnabled or State.emotesWalkEnabled then
State.currentEmoteTrack:Play()
if State.speedEmoteEnabled then
local speedValue = tonumber(UI.SpeedBox.Text) or 1
State.currentEmoteTrack:AdjustSpeed(speedValue)
end
end
end
end
playRandomEmote = function(humanoid, emoteId)
stopCurrentEmote()
stopEmotes()
local ok, track = pcall(function()
return humanoid:PlayEmoteAndGetAnimTrackById(emoteId)
end)
if ok and track and typeof(track) == "Instance" and track:IsA("AnimationTrack") then
State.currentEmoteTrack = track
if State.speedEmoteEnabled then
local speedVal = tonumber(UI.SpeedBox.Text) or Config.EmoteSpeed or 1
track:AdjustSpeed(speedVal)
end
end
end
function onCharacterAdded(character)
State.currentCharacter = character
stopCurrentEmote()
local humanoid = character:WaitForChild("Humanoid")
local animator = humanoid:WaitForChild("Animator")
if getgenv().autoReloadEnabled and getgenv().lastPlayedAnimation then
task.spawn(function()
local player = game.Players.LocalPlayer
if not player:HasAppearanceLoaded() then
player.CharacterAppearanceLoaded:Wait()
end
local animate = character:WaitForChild("Animate")
character:WaitForChild("HumanoidRootPart")
applyAnimation(getgenv().lastPlayedAnimation)
getgenv().Notify({
Title = '7yd7 | Auto Reload Animation',
Content = '🔄 The last animation was automatically \n reapplied',
Duration = 3
})
local lastAnim = getgenv().lastPlayedAnimation
local cacheKey = tostring(lastAnim.id)
local changed = false
for i = 1, 7 do
task.wait(0.01)
if not character or not character.Parent or not humanoid then break end
local mappings = State.AnimationCache[cacheKey]
if mappings and animate and animate.Parent then
for _, m in pairs(mappings) do
local categoryFolder = animate:FindFirstChild(m.category)
if categoryFolder then
for _, animObj in ipairs(categoryFolder:GetChildren()) do
if animObj:IsA("Animation") then
if animObj.AnimationId ~= m.animationId then
animObj.AnimationId = m.animationId
changed = true
end
end
end
end
end
end
end
--[[
if changed and humanoid.MoveDirection.Magnitude == 0 then
animate.Disabled = true
animate.Disabled = false
end
--]]
end)
end
animator.AnimationPlayed:Connect(function(animationTrack)
if isDancing(character, animationTrack) then
local playedEmoteId = urlToId(animationTrack.Animation.AnimationId)
if playedEmoteId == "" or playedEmoteId == "0" then return end
if State.emotesWalkEnabled then
if State.currentEmoteTrack then
local currentEmoteId = urlToId(State.currentEmoteTrack.Animation.AnimationId)
if currentEmoteId == playedEmoteId then
return
else
stopCurrentEmote()
end
end
playEmote(humanoid, playedEmoteId)
if currentEmoteTrack then
currentEmoteTrack.Ended:Connect(function()
if currentEmoteTrack == animationTrack then
currentEmoteTrack = nil
end
end)
end
end
if State.speedEmoteEnabled and not State.emotesWalkEnabled then
if State.currentEmoteTrack then
local currentEmoteId = urlToId(State.currentEmoteTrack.Animation.AnimationId)
if currentEmoteId == playedEmoteId then
return
else
stopCurrentEmote()
end
end
playEmote(humanoid, playedEmoteId)
if currentEmoteTrack then
currentEmoteTrack.Ended:Connect(function()
if currentEmoteTrack == animationTrack then
currentEmoteTrack = nil
end
end)
end
end
end
end)
humanoid.Died:Connect(function()
if State.hudEditorActive and exitHUDEditor then exitHUDEditor() end
State.emotesWalkEnabled = false
State.speedEmoteEnabled = false
State.favoriteEnabled = false
State.currentEmoteTrack = nil
stopEmotes()
stopCurrentEmote()
end)
end
function toggleEmoteWalk()
State.emotesWalkEnabled = not State.emotesWalkEnabled
ApplyFreezeButtonVisual()
if State.emotesWalkEnabled then
getgenv().Notify({
Title = '7yd7 | Emote Freeze',
Content = "🔒 Emote freeze ON",
Duration = 5
})
task.wait(0.1)
stopCurrentEmote()
if State.currentEmoteTrack and State.currentEmoteTrack.IsPlaying then
State.currentEmoteTrack:AdjustSpeed(1)
end
else
getgenv().Notify({
Title = '7yd7 | Emote Freeze',
Content = '🔓 Emote freeze OFF',
Duration = 5
})
task.wait(0.1)
stopCurrentEmote()
if State.currentEmoteTrack and State.currentEmoteTrack.IsPlaying and State.speedEmoteEnabled then
local speedValue = tonumber(UI.SpeedBox.Text) or 1
State.currentEmoteTrack:AdjustSpeed(speedValue)
elseif State.currentEmoteTrack and State.currentEmoteTrack.IsPlaying then
State.currentEmoteTrack:AdjustSpeed(1)
end
end
end
function toggleSpeedEmote()
State.speedEmoteEnabled = not State.speedEmoteEnabled
updateSpeedBoxVisibility()
if State.speedEmoteEnabled then
getgenv().Notify({
Title = '7yd7 | Speed Emote',
Content = "⚡ Speed Emote ON",
Duration = 5
})
task.wait(0.1)
stopCurrentEmote()
else
getgenv().Notify({
Title = '7yd7 | Speed Emote',
Content = '⚡ Speed Emote OFF',
Duration = 5
})
task.wait(0.1)
stopCurrentEmote()
end
Config.EmoteSpeedEnabled = State.speedEmoteEnabled
Config.EmoteSpeed = tonumber(UI.SpeedBox.Text) or 1
SaveConfig()
end
function toggleFavoriteMode()
State.favoriteEnabled = not State.favoriteEnabled
if State.favoriteEnabled then
ApplyFavoriteButtonVisual()
getgenv().Notify({
Title = '7yd7 | Favorite System',
Content = "🔒 Favorite ON",
Duration = 5
})
updateScriptPriorityOverlay()
setEmotesButtonsActiveForFavorites()
if State.currentMode == "emote" then
setupEmoteClickDetection()
else
updateAllFavoriteIcons()
end
else
ApplyFavoriteButtonVisual()
getgenv().Notify({
Title = '7yd7 | Favorite System',
Content = '🔓 Favorite OFF',
Duration = 3
})
if State.currentMode == "emote" then
stopEmoteClickDetection()
else
updateAllFavoriteIcons()
end
clearCustomHitboxes()
updateScriptPriorityOverlay()
end
pcall(function()
local frontFrame = CoreGui.RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
applyEmotesButtonsActiveState()
end)
end
local clickCooldown = {}
local CLICK_COOLDOWN_TIME = 0.1
function safeButtonClick(buttonName, callback)
if State.hudEditorActive then return end
local currentTime = tick()
if not clickCooldown[buttonName] or (currentTime - clickCooldown[buttonName]) > CLICK_COOLDOWN_TIME then
clickCooldown[buttonName] = currentTime
callback()
end
end
function setupAnimationClickDetection()
if State.isMonitoringClicks then
return
end
if State.currentMode == "animation" then
State.animationMonitorToken = State.animationMonitorToken + 1
local token = State.animationMonitorToken
State.isMonitoringClicks = true
task.spawn(function()
monitorAnimations(token)
end)
end
end
function toggleAutoReload()
getgenv().autoReloadEnabled = not getgenv().autoReloadEnabled
Config.AutoReloadEnabled = getgenv().autoReloadEnabled
task.spawn(SaveConfig)
if getgenv().autoReloadEnabled then
getgenv().Notify({
Title = '7yd7 | Auto Reload Animation',
Content = "🔄 Auto Reload ON",
Duration = 5
})
else
getgenv().Notify({
Title = '7yd7 | Auto Reload Animation',
Content = '🔄 Auto Reload OFF',
Duration = 3
})
end
end
function connectEvents()
disconnectAllConnections()
if UI._1left then
table.insert(State.guiConnections, UI._1left.MouseButton1Click:Connect(function()
safeButtonClick("PrevPage", previousPage)
end))
end
if UI._9right then
table.insert(State.guiConnections, UI._9right.MouseButton1Click:Connect(function()
safeButtonClick("NextPage", nextPage)
end))
end
if UI._2Routenumber then
table.insert(State.guiConnections, UI._2Routenumber.FocusLost:Connect(function(enterPressed)
if State.hudEditorActive then return end
local pageNum = tonumber(UI._2Routenumber.Text)
if pageNum then
goToPage(pageNum)
else
UI._2Routenumber.Text = tostring(State.currentPage)
end
end))
end
if UI.Search then
table.insert(State.guiConnections, UI.Search.Changed:Connect(function(property)
if State.hudEditorActive then return end
if property == "Text" then
if State.suppressSearch then
return
end
if State.currentMode == "emote" then
State.emoteSearchTerm = UI.Search.Text
searchEmotes(State.emoteSearchTerm)
else
State.animationSearchTerm = UI.Search.Text
searchAnimations(State.animationSearchTerm)
end
end
end))
end
local SECTOR_COUNT = 8
local SECTOR_ANGLE = 360 / SECTOR_COUNT
local function isAuthenticPageActive()
if not (Config.AuthenticFirstPage and State.currentMode == "emote") then
return false
end
local authenticEmotes = getgenv().OwnedAuthenticEmotes or {}
local authenticPagesCount = calcPagesForList(#authenticEmotes, false)
return #authenticEmotes > 0 and State.currentPage <= authenticPagesCount
end
table.insert(State.guiConnections, UserInputService.InputBegan:Connect(function(input, gameProcessed)
if State.hudEditorActive then return end
if input.UserInputType ~= Enum.UserInputType.MouseButton1 and input.UserInputType ~= Enum.UserInputType.Touch then return end
local exists, emotesWheel = checkEmotesMenuExists()
local isRecentlyVisible = (tick() - State.lastWheelVisibleTime < 0.15)
if not (exists and (emotesWheel.Visible or isRecentlyVisible)) then return end
local actualPos = Vector2.new(input.Position.X, input.Position.Y)
local absPos = emotesWheel.AbsolutePosition
local absSize = emotesWheel.AbsoluteSize
local inXBounds = (actualPos.X >= absPos.X) and (actualPos.X <= absPos.X + absSize.X)
local inYBounds = (actualPos.Y >= absPos.Y) and (actualPos.Y <= absPos.Y + absSize.Y)
if not (inXBounds and inYBounds) then return end
local center = absPos + (absSize / 2)
local dx = actualPos.X - center.X
local dy = actualPos.Y - center.Y
local distance = math.sqrt(dx*dx + dy*dy)
local radius = math.min(absSize.X, absSize.Y) * 0.5
if distance > radius then return end
local dynamicDeadzone = radius * 0.2
if distance < dynamicDeadzone then return end
local angle = math.deg(math.atan2(dy, dx))
local correctedAngle = (angle + 90 + (SECTOR_ANGLE / 2)) % 360
local index = math.floor(correctedAngle / SECTOR_ANGLE) + 1
if not (State.favoriteEnabled or State.currentMode == "animation" or isAuthenticPageActive() or (index == 1 and isRandomSlotActive())) then return end
handleSectorAction(index)
end))
local function bindWheelHotkeys()
if not ContextActionService then return end
local keyToIndex = {
[Enum.KeyCode.One] = 1, [Enum.KeyCode.Two] = 2, [Enum.KeyCode.Three] = 3, [Enum.KeyCode.Four] = 4,
[Enum.KeyCode.Five] = 5, [Enum.KeyCode.Six] = 6, [Enum.KeyCode.Seven] = 7, [Enum.KeyCode.Eight] = 8,
[Enum.KeyCode.KeypadOne] = 1, [Enum.KeyCode.KeypadTwo] = 2, [Enum.KeyCode.KeypadThree] = 3, [Enum.KeyCode.KeypadFour] = 4,
[Enum.KeyCode.KeypadFive] = 5, [Enum.KeyCode.KeypadSix] = 6, [Enum.KeyCode.KeypadSeven] = 7, [Enum.KeyCode.KeypadEight] = 8
}
local function onHotkey(actionName, inputState, inputObject)
if inputState ~= Enum.UserInputState.Begin then return Enum.ContextActionResult.Pass end
if State.hudEditorActive then return Enum.ContextActionResult.Pass end
if UserInputService:GetFocusedTextBox() then return Enum.ContextActionResult.Pass end
if State.customAnimationEditorActive and (not State.customAnimationEditingKey or not State.customAnimationEditingName or not (State.CustomAnimOverlay and State.CustomAnimOverlay.Parent)) then
if State.exitCustomAnimationEditor then
State.exitCustomAnimationEditor()
else
State.customAnimationEditorActive = false
end
end
local index = keyToIndex[inputObject.KeyCode]
if not index then return Enum.ContextActionResult.Pass end
if isAuthenticPageActive() then
return Enum.ContextActionResult.Pass
end
if not (State.favoriteEnabled or State.currentMode == "animation" or (index == 1 and isRandomSlotActive())) then
return Enum.ContextActionResult.Pass
end
local exists, emotesWheel = checkEmotesMenuExists()
local isRecentlyVisible = (tick() - State.lastWheelVisibleTime < 0.15)
if not (exists and (emotesWheel.Visible or isRecentlyVisible)) then return Enum.ContextActionResult.Pass end
local success, frontFrame = pcall(function()
return game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Front.EmotesButtons
end)
if success and frontFrame then
local target = frontFrame:FindFirstChild(tostring(index))
if target and target:IsA("ImageLabel") and target.Image ~= "" then
handleSectorAction(index)
if State.currentMode == "animation" and not State.favoriteEnabled then
pcall(function()
game:GetService("GuiService"):SetEmotesMenuOpen(false)
end)
pcall(function()
game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Visible = false
end)
end
return Enum.ContextActionResult.Sink
end
end
return Enum.ContextActionResult.Pass
end
ContextActionService:UnbindAction("7yd7_EmoteWheelHotkeys")
ContextActionService:BindActionAtPriority(
"7yd7_EmoteWheelHotkeys",
onHotkey,
false,
(Enum.ContextActionPriority.High.Value + 50),
Enum.KeyCode.One, Enum.KeyCode.Two, Enum.KeyCode.Three, Enum.KeyCode.Four,
Enum.KeyCode.Five, Enum.KeyCode.Six, Enum.KeyCode.Seven, Enum.KeyCode.Eight,
Enum.KeyCode.KeypadOne, Enum.KeyCode.KeypadTwo, Enum.KeyCode.KeypadThree, Enum.KeyCode.KeypadFour,
Enum.KeyCode.KeypadFive, Enum.KeyCode.KeypadSix, Enum.KeyCode.KeypadSeven, Enum.KeyCode.KeypadEight
)
end
bindWheelHotkeys()
if UI.EmoteWalkButton then
table.insert(State.guiConnections, UI.EmoteWalkButton.MouseButton1Click:Connect(function()
safeButtonClick("EmoteWalk", toggleEmoteWalk)
end))
end
if UI.Favorite then
table.insert(State.guiConnections, UI.Favorite.MouseButton1Click:Connect(function()
safeButtonClick("Favorite", toggleFavoriteMode)
end))
end
if UI.SpeedEmote then
table.insert(State.guiConnections, UI.SpeedEmote.MouseButton1Click:Connect(function()
safeButtonClick("SpeedEmote", toggleSpeedEmote)
end))
end
if UI.Reload then
table.insert(State.guiConnections, UI.Reload.MouseButton1Click:Connect(function()
safeButtonClick("AutoReload", toggleAutoReload)
end))
end
if UI.Changepage then
table.insert(State.guiConnections, UI.Changepage.MouseButton1Click:Connect(function()
safeButtonClick("ChangePage", function()
stopEmoteClickDetection()
if State.animImageSpamConn then
State.animImageSpamConn:Disconnect()
State.animImageSpamConn = nil
State.animImageSpamMap = nil
State.animImageSpamTicks = nil
State.animImageSpamToken = State.animImageSpamToken + 1
end
if State.currentMode == "emote" then
State.currentMode = "animation"
local function applyAnimationModeUI()
State.suppressSearch = true
UI.Search.Text = State.animationSearchTerm
State.suppressSearch = false
State.currentPage = Config.AnimationPage or 1
State.totalPages = calculateTotalPages()
updatePageDisplay()
updateEmotes()
updateScriptPriorityOverlay()
State.animationMonitorToken = State.animationMonitorToken + 1
local token = State.animationMonitorToken
State.isMonitoringClicks = true
task.spawn(function()
monitorAnimations(token)
end)
end
applyAnimationModeUI()
local beforeVersion = State.animationCacheVersion
task.spawn(function()
fetchAllAnimations()
if State.currentMode ~= "animation" then return end
if State.animationCacheVersion ~= beforeVersion then
applyAnimationModeUI()
end
end)
getgenv().Notify({
Title = '7yd7 | Animation',
Content = '📄 Changed to Emote > Animation Mode',
Duration = 3
})
else
State.currentMode = "emote"
clearCustomHitboxes()
State.suppressSearch = true
UI.Search.Text = State.emoteSearchTerm
State.suppressSearch = false
State.currentPage = Config.EmotePage or 1
State.totalPages = calculateTotalPages()
updatePageDisplay()
updateEmotes()
updateScriptPriorityOverlay()
if State.favoriteEnabled then
setupEmoteClickDetection()
end
getgenv().Notify({
Title = '7yd7 | Emote',
Content = '📄 Changed to Animation > Emote Mode',
Duration = 3
})
end
end)
end))
end
if UI.SpeedBox then
table.insert(State.guiConnections, UI.SpeedBox.FocusLost:Connect(function()
if State.hudEditorActive then return end
local speedValue = tonumber(UI.SpeedBox.Text) or 1
Config.EmoteSpeed = speedValue
SaveConfig()
end))
end
end
function calculateSnap(element, newPos, currentName, allMovable)
local SNAP_THRESHOLD = 8
local parent = element.Parent
if not parent then return newPos, nil, nil end
local ps = parent.AbsoluteSize
local pp = parent.AbsolutePosition
local absX = pp.X + newPos.X.Scale * ps.X + newPos.X.Offset
local absY = pp.Y + newPos.Y.Scale * ps.Y + newPos.Y.Offset
local absW = element.AbsoluteSize.X
local absH = element.AbsoluteSize.Y
local sX, sY = absX, absY
local didX, didY = false, false
local guideX, guideY
for oName, oEl in pairs(allMovable) do
if oName ~= currentName then
local oX = oEl.AbsolutePosition.X
local oY = oEl.AbsolutePosition.Y
local oW = oEl.AbsoluteSize.X
local oH = oEl.AbsoluteSize.Y
if not didX then
if math.abs(absX - oX) < SNAP_THRESHOLD then sX = oX; didX = true; guideX = oX end
if math.abs(absX - (oX + oW)) < SNAP_THRESHOLD then sX = oX + oW; didX = true; guideX = oX + oW end
if math.abs((absX + absW) - oX) < SNAP_THRESHOLD then sX = oX - absW; didX = true; guideX = oX end
if math.abs((absX + absW) - (oX + oW)) < SNAP_THRESHOLD then sX = oX + oW - absW; didX = true; guideX = oX + oW end
if math.abs((absX + absW/2) - (oX + oW/2)) < SNAP_THRESHOLD then sX = oX + oW/2 - absW/2; didX = true; guideX = oX + oW/2 end
end
if not didY then
if math.abs(absY - oY) < SNAP_THRESHOLD then sY = oY; didY = true; guideY = oY end
if math.abs(absY - (oY + oH)) < SNAP_THRESHOLD then sY = oY + oH; didY = true; guideY = oY + oH end
if math.abs((absY + absH) - oY) < SNAP_THRESHOLD then sY = oY - absH; didY = true; guideY = oY end
if math.abs((absY + absH) - (oY + oH)) < SNAP_THRESHOLD then sY = oY + oH - absH; didY = true; guideY = oY + oH end
if math.abs((absY + absH/2) - (oY + oH/2)) < SNAP_THRESHOLD then sY = oY + oH/2 - absH/2; didY = true; guideY = oY + oH/2 end
end
end
end
local fsx = (sX - pp.X) / ps.X
local fsy = (sY - pp.Y) / ps.Y
return UDim2.new(fsx, newPos.X.Offset, fsy, newPos.Y.Offset), guideX, guideY
end
local function hudColorToRGB(c)
return {math.floor(c.R * 255 + 0.5), math.floor(c.G * 255 + 0.5), math.floor(c.B * 255 + 0.5)}
end
local function copyProps(name)
local src = Config.HUDProperties and Config.HUDProperties[name]
if not src then return {} end
local out = {}
for k, v in pairs(src) do
if type(v) == "table" then
local t = {}
for i, sv in pairs(v) do
t[i] = sv
end
out[k] = t
else
out[k] = v
end
end
return out
end
local function captureHUDState(n, el)
if not n or not el then return nil end
local cR = el:FindFirstChildWhichIsA("UICorner")
local s = {
name = n,
pos = el.Position,
size = el.Size,
z = el.ZIndex,
bgTrans = el.BackgroundTransparency,
bgColor = el.BackgroundColor3,
radius = cR and cR.CornerRadius or nil
}
if el:IsA("ImageLabel") or el:IsA("ImageButton") then
s.imgTrans = el.ImageTransparency
s.imgColor = el.ImageColor3
end
if el:IsA("TextLabel") or el:IsA("TextBox") then
s.text = el.Text
s.textTrans = el.TextTransparency
s.textColor = el.TextColor3
if el:IsA("TextBox") then
s.placeholder = el.PlaceholderText
end
end
s.props = copyProps(n)
return s
end
local function pushUndo(state)
if not state then return end
if not HUD.UndoStack then HUD.UndoStack = {} end
table.insert(HUD.UndoStack, state)
if #HUD.UndoStack > 50 then
table.remove(HUD.UndoStack, 1)
end
end
local function sameUDim2(a, b)
return a.X.Scale == b.X.Scale and a.X.Offset == b.X.Offset and a.Y.Scale == b.Y.Scale and a.Y.Offset == b.Y.Offset
end
local function sameUDim(a, b)
return a.Scale == b.Scale and a.Offset == b.Offset
end
local function sameColor(a, b)
return math.abs(a.R - b.R) < 0.001 and math.abs(a.G - b.G) < 0.001 and math.abs(a.B - b.B) < 0.001
end
local function applyHUDState(state)
if not state or not state.name then return end
local all = getAllHUDObjects()
local el = all[state.name]
if not el then return end
if state.pos then
el.Position = state.pos
if not Config.HUDPositions then Config.HUDPositions = {} end
Config.HUDPositions[state.name] = {state.pos.X.Scale, state.pos.X.Offset, state.pos.Y.Scale, state.pos.Y.Offset}
end
if state.size then
el.Size = state.size
if not Config.HUDSizes then Config.HUDSizes = {} end
Config.HUDSizes[state.name] = {state.size.X.Scale, state.size.X.Offset, state.size.Y.Scale, state.size.Y.Offset}
end
if state.z ~= nil then el.ZIndex = state.z end
if state.props and state.props.BgTrans ~= nil then el.BackgroundTransparency = state.bgTrans end
if state.props and state.props.BgColor then el.BackgroundColor3 = state.bgColor end
if el:IsA("ImageLabel") or el:IsA("ImageButton") then
if state.props and state.props.ImgTrans ~= nil then el.ImageTransparency = state.imgTrans end
if state.props and state.props.ImgColor then el.ImageColor3 = state.imgColor end
end
if el:IsA("TextLabel") or el:IsA("TextBox") then
if state.props and state.props.Text ~= nil then el.Text = state.text end
if state.props and state.props.TextTransparency ~= nil then el.TextTransparency = state.textTrans end
if state.props and state.props.TxtColor then el.TextColor3 = state.textColor end
if el:IsA("TextBox") and state.placeholder ~= nil then
el.PlaceholderText = state.placeholder
end
end
if state.radius then
local cR = el:FindFirstChildWhichIsA("UICorner")
if cR then cR.CornerRadius = state.radius end
end
if not Config.HUDProperties then Config.HUDProperties = {} end
Config.HUDProperties[state.name] = state.props or {}
SaveConfig()
pcall(function() updateGUIColors() end)
end
local function undoLastHUD()
if not State.hudEditorActive then return end
if not HUD.UndoStack or #HUD.UndoStack == 0 then return end
local state = table.remove(HUD.UndoStack)
applyHUDState(state)
end
local function normalizeUDim2(u, ps)
if not u or not ps or ps.X <= 0 or ps.Y <= 0 then
return nil
end
local sx = u.X.Scale + (u.X.Offset / ps.X)
local sy = u.Y.Scale + (u.Y.Offset / ps.Y)
return sx, 0, sy, 0
end
local function tableToUDim2(v)
if type(v) ~= "table" or #v ~= 4 then return nil end
return UDim2.new(v[1], v[2], v[3], v[4])
end
local function normalizeHUDScale()
local elems = getAllHUDObjects()
for name, el in pairs(elems) do
local parent = el and el.Parent
if parent then
local hasLayout = parent:FindFirstChildOfClass("UIListLayout")
if hasLayout and not HUD.IsUnlocked then
return
end
local ps = parent.AbsoluteSize
if Config.HUDPositions and Config.HUDPositions[name] then
local v = Config.HUDPositions[name]
if type(v) == "table" and #v == 4 then
local sx, ox, sy, oy = v[1], v[2], v[3], v[4]
if ox ~= 0 or oy ~= 0 then
local nsx, nox, nsy, noy = normalizeUDim2(UDim2.new(sx, ox, sy, oy), ps)
if nsx then
Config.HUDPositions[name] = {nsx, nox, nsy, noy}
el.Position = UDim2.new(nsx, nox, nsy, noy)
end
end
end
end
if Config.HUDSizes and Config.HUDSizes[name] then
local v = Config.HUDSizes[name]
if type(v) == "table" and #v == 4 then
local def = HUD.DefaultSizes and HUD.DefaultSizes[name]
local isDefault = def and sameUDim2(def, tableToUDim2(v) or UDim2.new(0,0,0,0))
if isDefault then
return
end
local sx, ox, sy, oy = v[1], v[2], v[3], v[4]
if ox ~= 0 or oy ~= 0 then
local nsx, nox, nsy, noy = normalizeUDim2(UDim2.new(sx, ox, sy, oy), ps)
if nsx then
Config.HUDSizes[name] = {nsx, nox, nsy, noy}
el.Size = UDim2.new(nsx, nox, nsy, noy)
end
end
end
end
end
end
SaveConfig()
end
local function normalizeHUDScaleForElement(name, el, normalizePos, normalizeSize)
if not name or not el or not el.Parent then return end
if normalizePos == nil then normalizePos = true end
if normalizeSize == nil then normalizeSize = true end
local parent = el.Parent
local hasLayout = parent:FindFirstChildOfClass("UIListLayout")
if hasLayout and not HUD.IsUnlocked then return end
local ps = parent.AbsoluteSize
if ps.X <= 0 or ps.Y <= 0 then return end
if normalizePos then
local nsx, nox, nsy, noy = normalizeUDim2(el.Position, ps)
if nsx then
el.Position = UDim2.new(nsx, nox, nsy, noy)
if not Config.HUDPositions then Config.HUDPositions = {} end
Config.HUDPositions[name] = {nsx, nox, nsy, noy}
end
end
if normalizeSize then
local nsx, nox, nsy, noy = normalizeUDim2(el.Size, ps)
if nsx then
el.Size = UDim2.new(nsx, nox, nsy, noy)
if not Config.HUDSizes then Config.HUDSizes = {} end
Config.HUDSizes[name] = {nsx, nox, nsy, noy}
end
end
SaveConfig()
end
function selectHUDElement(name, element)
if HUD.SelectedElement == element then return end
HUD.SelectedElement = element
HUD.LastTouchedElement = element
HUD.LastTouchedName = name
local parent = element.Parent
if UI and parent and (parent == UI.Top or parent == UI.Under) then
local key = parent.Name
local l = parent:FindFirstChildOfClass("UIListLayout") or (HUD.Layouts and HUD.Layouts[key])
if l then
HUD.Layouts[key] = l
HUD.LayoutsRemoved[key] = true
l.Parent = nil
end
end
for _, h in pairs(HUD.ResizeHandles) do pcall(function() h:Destroy() end) end
HUD.ResizeHandles = {}
for _, c in pairs(HUD.ResizeConnections) do pcall(function() c:Disconnect() end) end
HUD.ResizeConnections = {}
local selectionGui = HUD.SelectionGui
local wrapper = Instance.new("Frame")
wrapper.Name = "SelectionWrapper"
wrapper.BackgroundTransparency = 1
wrapper.ZIndex = 1
wrapper.Parent = selectionGui
table.insert(HUD.ResizeHandles, wrapper)
table.insert(HUD.ResizeConnections, RunService.RenderStepped:Connect(function()
if HUD.SelectedElement == element and element.Parent then
wrapper.Size = UDim2.fromOffset(element.AbsoluteSize.X, element.AbsoluteSize.Y)
wrapper.Position = UDim2.fromOffset(element.AbsolutePosition.X, element.AbsolutePosition.Y)
end
end))
local handlePositions = {
TopLeft = {UDim2.new(0,0,0,0), Vector2.new(-1, -1)},
Top = {UDim2.new(0.5,0,0,0), Vector2.new(0, -1)},
TopRight = {UDim2.new(1,0,0,0), Vector2.new(1, -1)},
Left = {UDim2.new(0,0,0.5,0), Vector2.new(-1, 0)},
Right = {UDim2.new(1,0,0.5,0), Vector2.new(1, 0)},
BottomLeft = {UDim2.new(0,0,1,0), Vector2.new(-1, 1)},
Bottom = {UDim2.new(0.5,0,1,0), Vector2.new(0, 1)},
BottomRight = {UDim2.new(1,0,1,0), Vector2.new(1, 1)}
}
for dir, data in pairs(handlePositions) do
local h = Instance.new("Frame")
h.Name = "Resize_"..dir
h.Size = UDim2.new(0, 8, 0, 8)
h.AnchorPoint = Vector2.new(0.5, 0.5)
h.Position = data[1]
h.BackgroundColor3 = Color3.fromRGB(0, 255, 100)
h.BorderColor3 = Color3.fromRGB(0, 0, 0)
h.ZIndex = 11000
h.Parent = wrapper
local btn = Instance.new("TextButton")
btn.Size = UDim2.new(1, 4, 1, 4)
btn.Position = UDim2.new(0.5, 0, 0.5, 0)
btn.AnchorPoint = Vector2.new(0.5, 0.5)
btn.BackgroundTransparency = 1
btn.Text = ""
btn.ZIndex = 11001
btn.Parent = h
local resizing = false
local dragStart
local startAbsSize
local startAbsPos
local resizeUndo
table.insert(HUD.ResizeConnections, btn.InputBegan:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
resizing = true
resizeUndo = captureHUDState(name, element)
dragStart = input.Position
startAbsSize = element.AbsoluteSize
startAbsPos = element.AbsolutePosition
end
end))
table.insert(HUD.ResizeConnections, UserInputService.InputChanged:Connect(function(input)
if not resizing then return end
if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
local delta = input.Position - dragStart
local pSize = element.Parent and element.Parent.AbsoluteSize or Vector2.new(1, 1)
local dirVec = data[2]
local newW = startAbsSize.X + (dirVec.X == 1 and delta.X or (dirVec.X == -1 and -delta.X or 0))
local newH = startAbsSize.Y + (dirVec.Y == 1 and delta.Y or (dirVec.Y == -1 and -delta.Y or 0))
local newX = startAbsPos.X + (dirVec.X == -1 and delta.X or 0)
local newY = startAbsPos.Y + (dirVec.Y == -1 and delta.Y or 0)
if newW < 20 then
if dirVec.X == -1 then newX = newX - (20 - newW) end
newW = 20
end
if newH < 20 then
if dirVec.Y == -1 then newY = newY - (20 - newH) end
newH = 20
end
local parentPos = element.Parent and element.Parent.AbsolutePosition or Vector2.new(0,0)
local relX = (newX - parentPos.X) / pSize.X
local relY = (newY - parentPos.Y) / pSize.Y
element.Size = UDim2.new(newW / pSize.X, 0, newH / pSize.Y, 0)
element.Position = UDim2.new(relX, 0, relY, 0)
end
end))
table.insert(HUD.ResizeConnections, UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
if resizing then
resizing = false
if resizeUndo and (not sameUDim2(resizeUndo.pos, element.Position) or not sameUDim2(resizeUndo.size, element.Size)) then
pushUndo(resizeUndo)
end
local rPs = element.Parent and element.Parent.AbsoluteSize or Vector2.new(1, 1)
local pXs = element.Position.X.Scale + (element.Position.X.Offset / rPs.X)
local pYs = element.Position.Y.Scale + (element.Position.Y.Offset / rPs.Y)
Config.HUDPositions[name] = {pXs, 0, pYs, 0}
if not Config.HUDSizes then Config.HUDSizes = {} end
local sXs = element.Size.X.Scale + (element.Size.X.Offset / rPs.X)
local sYs = element.Size.Y.Scale + (element.Size.Y.Offset / rPs.Y)
Config.HUDSizes[name] = {sXs, 0, sYs, 0}
end
end
end))
end
end
function setupElementDragging(name, element, allMovable, snapGuideV, snapGuideH)
element.Visible = true
local stroke = Instance.new("UIStroke")
stroke.Name = "HUDEditorStroke"
stroke.Color = Color3.fromRGB(0, 255, 100)
stroke.Thickness = 2
stroke.Parent = element
table.insert(HUD.Strokes, stroke)
local isChild = false
for _, friendly in pairs(HUD.FriendlyNames) do
if name == friendly then
isChild = true
break
end
end
local inputTarget = Instance.new("TextButton")
inputTarget.Name = "HUDDragHandle_" .. name
inputTarget.BackgroundTransparency = 1
inputTarget.Text = ""
inputTarget.ZIndex = isChild and 10 or 5
inputTarget.Active = true
inputTarget.Parent = HUD.SelectionGui
table.insert(HUD.Connections, RunService.RenderStepped:Connect(function()
if element and element.Parent then
inputTarget.Size = UDim2.fromOffset(element.AbsoluteSize.X, element.AbsoluteSize.Y)
inputTarget.Position = UDim2.fromOffset(element.AbsolutePosition.X, element.AbsolutePosition.Y)
end
end))
local dragging = false
local dragStart, startPos
local dragUndo
table.insert(HUD.Connections, inputTarget.InputBegan:Connect(function(input)
if not State.hudEditorActive then return end
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
dragging = true
dragUndo = captureHUDState(name, element)
dragStart = input.Position
startPos = element.Position
stroke.Color = Color3.fromRGB(255, 255, 255)
selectHUDElement(name, element)
end
end))
table.insert(HUD.Connections, UserInputService.InputChanged:Connect(function(input)
if not dragging then return end
if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then
if not dragStart then return end
local delta = input.Position - dragStart
local ps = element.Parent and element.Parent.AbsoluteSize or Vector2.new(1, 1)
local rawPos = UDim2.new(
startPos.X.Scale + delta.X / ps.X, startPos.X.Offset,
startPos.Y.Scale + delta.Y / ps.Y, startPos.Y.Offset
)
local snapped, gx, gy = calculateSnap(element, rawPos, name, allMovable)
element.Position = snapped
local ovP = HUD.Overlay and HUD.Overlay.AbsolutePosition or Vector2.new(0, 0)
if snapGuideV then snapGuideV.Visible = (gx ~= nil); if gx then snapGuideV.Position = UDim2.fromOffset(gx - ovP.X, 0) end end
if snapGuideH then snapGuideH.Visible = (gy ~= nil); if gy then snapGuideH.Position = UDim2.fromOffset(0, gy - ovP.Y) end end
end
end))
table.insert(HUD.Connections, UserInputService.InputEnded:Connect(function(input)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
if dragging then
dragging = false
stroke.Color = Color3.fromRGB(0, 255, 100)
if snapGuideV then snapGuideV.Visible = false end
if snapGuideH then snapGuideH.Visible = false end
if dragUndo and not sameUDim2(dragUndo.pos, element.Position) then
pushUndo(dragUndo)
end
local dPs = element.Parent and element.Parent.AbsoluteSize or Vector2.new(1, 1)
local dpXs = element.Position.X.Scale + (element.Position.X.Offset / dPs.X)
local dpYs = element.Position.Y.Scale + (element.Position.Y.Offset / dPs.Y)
element.Position = UDim2.new(dpXs, 0, dpYs, 0)
Config.HUDPositions[name] = {dpXs, 0, dpYs, 0}
end
end
end))
end
applySavedPositions = function()
local elems = getAllHUDObjects()
for name, el in pairs(elems) do
local customPos = Config.HUDPositions and Config.HUDPositions[name]
if customPos and type(customPos) == "table" and #customPos == 4 then
el.Position = UDim2.new(customPos[1], customPos[2], customPos[3], customPos[4])
elseif HUD.DefaultPositions and HUD.DefaultPositions[name] then
el.Position = HUD.DefaultPositions[name]
end
local customSz = Config.HUDSizes and Config.HUDSizes[name]
if customSz and type(customSz) == "table" and #customSz == 4 then
el.Size = UDim2.new(customSz[1], customSz[2], customSz[3], customSz[4])
elseif HUD.DefaultSizes and HUD.DefaultSizes[name] then
el.Size = HUD.DefaultSizes[name]
end
local props = Config.HUDProperties and Config.HUDProperties[name]
if props then
for k, v in pairs(props) do
pcall(function()
if k == "Radius" or k == "CornerRadius" then
local cR = el:FindFirstChildWhichIsA("UICorner")
if cR and type(v) == "table" then
cR.CornerRadius = UDim.new(tonumber(v[1]) or 0, tonumber(v[2]) or 0)
end
elseif k == "RadiusString" or k == "PlaceholderTransparency" then
else
el[k] = v
end
end)
end
end
end
end
exitHUDEditor = function()
if not State.hudEditorActive then return end
State.hudEditorActive = false
if SettingsLib and SettingsLib.UI and SettingsLib.UI:IsA("ScreenGui") and HUD.SettingsDisplayOrderPrev ~= nil then
pcall(function()
SettingsLib.UI.DisplayOrder = HUD.SettingsDisplayOrderPrev
end)
HUD.SettingsDisplayOrderPrev = nil
end
for _, conn in pairs(HUD.Connections) do pcall(function() conn:Disconnect() end) end
HUD.Connections = {}
for _, conn in pairs(HUD.ResizeConnections) do pcall(function() conn:Disconnect() end) end
HUD.ResizeConnections = {}
for _, h in pairs(HUD.ResizeHandles) do pcall(function() h:Destroy() end) end
HUD.ResizeHandles = {}
HUD.SelectedElement = nil
for _, stroke in pairs(HUD.Strokes) do
pcall(function() if stroke and stroke.Parent then stroke:Destroy() end end)
end
HUD.Strokes = {}
if HUD.SelectionGui then
pcall(function() HUD.SelectionGui:Destroy() end)
HUD.SelectionGui = nil
end
for _, el in pairs(getMovableElements()) do
local h = el:FindFirstChild("HUDDragHandle")
if h then h:Destroy() end
if el:FindFirstChildOfClass("UIListLayout") then
for _, child in pairs(el:GetChildren()) do
if child:IsA("GuiButton") or child:IsA("TextBox") then
child.Active = true
end
end
end
end
if HUD.Overlay then
for _, g in pairs(HUD.Overlay:GetChildren()) do
if g.Name == "SnapGuide" then g:Destroy() end
end
end
if HUD.Overlay and HUD.Overlay.Parent then HUD.Overlay:Destroy() end
HUD.Overlay = nil
if HUD.ForceVisibleConn then HUD.ForceVisibleConn:Disconnect(); HUD.ForceVisibleConn = nil end
if UI.Search then UI.Search.TextEditable = true; UI.Search.Active = true end
if UI.SpeedBox then UI.SpeedBox.TextEditable = true; UI.SpeedBox.Active = true end
if UI._2Routenumber then UI._2Routenumber.TextEditable = true; UI._2Routenumber.Active = true end
pcall(function() game:GetService("GuiService"):SetEmotesMenuOpen(false) end)
pcall(function() game:GetService("CoreGui").RobloxGui.EmotesMenu.Children.Main.EmotesWheel.Visible = false end)
end
enterHUDEditor = function()
if State.hudEditorActive then return end
State.hudEditorActive = true
HUD.UndoStack = {}
GuiService:SetEmotesMenuOpen(false)
task.wait(0.15)
local exists, emotesWheel = checkEmotesMenuExists()
if not exists then State.hudEditorActive = false; return end
emotesWheel.Visible = true
HUD.ForceVisibleConn = RunService.Heartbeat:Connect(function()
if not State.hudEditorActive then return end
pcall(function()
local _, ew = checkEmotesMenuExists()
if ew then ew.Visible = true end
end)
end)
local main = getSettingsMainFrame()
if main then main.Visible = false end
syncToggleVisibility()
if SettingsLib and SettingsLib.UI and SettingsLib.UI:IsA("ScreenGui") then
if HUD.SettingsDisplayOrderPrev == nil then
HUD.SettingsDisplayOrderPrev = SettingsLib.UI.DisplayOrder
end
pcall(function() SettingsLib.UI.DisplayOrder = 99998 end)
end
ApplyUIVisibility()
local selectionGui = game:GetService("CoreGui"):FindFirstChild("7yd7_HUDSelection")
if not selectionGui then
selectionGui = Instance.new("ScreenGui")
selectionGui.Name = "7yd7_HUDSelection"
selectionGui.IgnoreGuiInset = false
selectionGui.DisplayOrder = 99999
selectionGui.Parent = game:GetService("CoreGui")
else
selectionGui.IgnoreGuiInset = false
selectionGui.DisplayOrder = 99999
end
HUD.SelectionGui = selectionGui
local overlay = Instance.new("Frame")
overlay.Name = "HUDEditorOverlay"
overlay.Parent = SettingsLib.UI
overlay.BackgroundTransparency = 1
overlay.Size = UDim2.fromScale(1, 1)
overlay.ZIndex = 6000
overlay.Active = false
HUD.Overlay = overlay
table.insert(HUD.Connections, UserInputService.InputBegan:Connect(function(input, gameProcessed)
if gameProcessed then return end
if not State.hudEditorActive then return end
if input.KeyCode == Enum.KeyCode.Z then
if UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or UserInputService:IsKeyDown(Enum.KeyCode.RightControl) then
undoLastHUD()
end
end
end))
table.insert(HUD.Connections, UserInputService.InputBegan:Connect(function(input, gameProcessed)
if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
local p = input.Position
if HUD.SelectedElement then
local e = HUD.SelectedElement
local pos = e.AbsolutePosition
local sz = e.AbsoluteSize
if p.X < pos.X - 25 or p.X > pos.X + sz.X + 25 or p.Y < pos.Y - 25 or p.Y > pos.Y + sz.Y + 25 then
task.delay(0.1, function()
if HUD.SelectedElement == e then
HUD.SelectedElement = nil
for _, h in pairs(HUD.ResizeHandles) do pcall(function() h:Destroy() end) end
HUD.ResizeHandles = {}
for _, c in pairs(HUD.ResizeConnections) do pcall(function() c:Disconnect() end) end
HUD.ResizeConnections = {}
end
end)
end
end
end
end))
local bc = Instance.new("Frame")
bc.Parent = overlay
bc.BackgroundTransparency = 1
bc.AnchorPoint = Vector2.new(1, 0)
bc.Position = UDim2.new(1, -10, 0, 10)
bc.Size = UDim2.fromOffset(360, 42)
bc.ZIndex = 6000
local bl = Instance.new("UIListLayout")
bl.FillDirection = Enum.FillDirection.Horizontal
bl.Padding = UDim.new(0, 8)
bl.HorizontalAlignment = Enum.HorizontalAlignment.Right
bl.VerticalAlignment = Enum.VerticalAlignment.Center
bl.Parent = bc
local propertiesBtn = Instance.new("ImageButton")
propertiesBtn.Parent = bc
propertiesBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
propertiesBtn.BackgroundTransparency = 0.4
propertiesBtn.Size = UDim2.fromOffset(42, 42)
propertiesBtn.Image = "rbxassetid://111026029750357"
propertiesBtn.ZIndex = 6001
local propCorner = Instance.new("UICorner")
propCorner.CornerRadius = UDim.new(0, 10)
propCorner.Parent = propertiesBtn
local exportBtn = Instance.new("ImageButton")
exportBtn.Parent = bc
exportBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
exportBtn.BackgroundTransparency = 0.4
exportBtn.Size = UDim2.fromOffset(42, 42)
exportBtn.Image = "rbxassetid://107588515524752"
exportBtn.ZIndex = 6001
local exportCorner = Instance.new("UICorner")
exportCorner.CornerRadius = UDim.new(0, 10)
exportCorner.Parent = exportBtn
local importBtn = Instance.new("ImageButton")
importBtn.Parent = bc
importBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
importBtn.BackgroundTransparency = 0.4
importBtn.Size = UDim2.fromOffset(42, 42)
importBtn.Image = "rbxassetid://78317476576895"
importBtn.ZIndex = 6001
local importCorner = Instance.new("UICorner")
importCorner.CornerRadius = UDim.new(0, 10)
importCorner.Parent = importBtn
local resetBtn = Instance.new("ImageButton")
resetBtn.Parent = bc
resetBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
resetBtn.BackgroundTransparency = 0.4
resetBtn.Size = UDim2.fromOffset(42, 42)
resetBtn.Image = "rbxassetid://123088523596870"
resetBtn.ZIndex = 6001
local resetCorner = Instance.new("UICorner")
resetCorner.CornerRadius = UDim.new(0, 10)
resetCorner.Parent = resetBtn
local lockBtn = Instance.new("ImageButton")
lockBtn.Parent = bc
lockBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
lockBtn.BackgroundTransparency = 0.4
lockBtn.Size = UDim2.fromOffset(42, 42)
lockBtn.Image = HUD.IsUnlocked and "rbxassetid://137042445663198" or "rbxassetid://137985778533954"
lockBtn.ZIndex = 6001
local lockCorner = Instance.new("UICorner")
lockCorner.CornerRadius = UDim.new(0, 10)
lockCorner.Parent = lockBtn
local addBtn = Instance.new("ImageButton")
addBtn.Parent = bc
addBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
addBtn.BackgroundTransparency = 0.4
addBtn.Size = UDim2.fromOffset(42, 42)
addBtn.Image = "rbxassetid://108445456753346"
addBtn.ZIndex = 6001
local addCorner = Instance.new("UICorner")
addCorner.CornerRadius = UDim.new(0, 10)
addCorner.Parent = addBtn
local backBtn = Instance.new("ImageButton")
backBtn.Parent = bc
backBtn.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
backBtn.BackgroundTransparency = 0.4
backBtn.Size = UDim2.fromOffset(42, 42)
backBtn.Image = "rbxassetid://79024388644722"
backBtn.ZIndex = 6001
local backCorner = Instance.new("UICorner")
backCorner.CornerRadius = UDim.new(0, 10)
backCorner.Parent = backBtn
local function rebuildHUDOverlays()
for _, conn in pairs(HUD.ResizeConnections) do pcall(function() conn:Disconnect() end) end
HUD.ResizeConnections = {}
for _, h in pairs(HUD.ResizeHandles) do pcall(function() h:Destroy() end) end
HUD.ResizeHandles = {}
for _, stroke in pairs(HUD.Strokes) do pcall(function() stroke:Destroy() end) end
HUD.Strokes = {}
if selectionGui then selectionGui:ClearAllChildren() end
HUD.SelectedElement = nil
local allMovable = getMovableElements()
local snapGuideH = Instance.new("Frame")
snapGuideH.Name = "SnapGuide"
snapGuideH.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
snapGuideH.BorderSizePixel = 0
snapGuideH.Size = UDim2.new(1, 0, 0, 1)
snapGuideH.ZIndex = 6002
snapGuideH.Visible = false
snapGuideH.Parent = selectionGui
local snapGuideV = Instance.new("Frame")
snapGuideV.Name = "SnapGuide"
snapGuideV.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
snapGuideV.BorderSizePixel = 0
snapGuideV.Size = UDim2.new(0, 1, 1, 0)
snapGuideV.ZIndex = 6002
snapGuideV.Visible = false
snapGuideV.Parent = selectionGui
for name, element in pairs(allMovable) do
setupElementDragging(name, element, allMovable, snapGuideV, snapGuideH)
end
updateHUDLayouts()
applySavedPositions()
end
local function rebuildCustomFramesFromConfig()
if UI.CustomFrames then
for _, frame in pairs(UI.CustomFrames) do
if frame and frame.Parent then frame:Destroy() end
end
end
UI.CustomFrames = {}
if not Config.CustomFrames then return end
local _, emotesWheel = checkEmotesMenuExists()
if not emotesWheel then return end
for name, data in pairs(Config.CustomFrames) do
local cf = Instance.new("Frame")
cf.Name = name
cf.Parent = emotesWheel
cf.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
cf.BackgroundTransparency = 0.4
cf.ZIndex = data and data.ZIndex or 3
cf.BorderSizePixel = 0
cf.Active = true
local pos = Config.HUDPositions and Config.HUDPositions[name]
local size = Config.HUDSizes and Config.HUDSizes[name]
if pos and type(pos) == "table" and #pos == 4 then
cf.Position = UDim2.new(pos[1], pos[2], pos[3], pos[4])
else
cf.Position = UDim2.new(0.5, 0, 0.5, 0)
end
if size and type(size) == "table" and #size == 4 then
cf.Size = UDim2.new(size[1], size[2], size[3], size[4])
else
cf.Size = UDim2.new(0.3, 0, 0.3, 0)
end
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 10)
corner.Parent = cf
UI.CustomFrames[name] = cf
HUD.DefaultPositions[name] = cf.Position
HUD.DefaultSizes[name] = cf.Size
end
end
local function applyHUDSettingsReplace(settings)
local function normalizeImportTable(tbl)
if type(tbl) ~= "table" then return {} end
local allElems = getAllHUDObjects()
for eName, v in pairs(tbl) do
if type(v) == "table" and #v == 4 then
local sx, ox, sy, oy = v[1], v[2], v[3], v[4]
if ox ~= 0 or oy ~= 0 then
local el = allElems[eName]
local ps = el and el.Parent and el.Parent.AbsoluteSize
if ps and ps.X > 0 and ps.Y > 0 then
tbl[eName] = {sx + (ox / ps.X), 0, sy + (oy / ps.Y), 0}
end
end
end
end
return tbl
end
Config.HUDPositions = normalizeImportTable(settings.HUDPositions or {})
Config.HUDSizes = normalizeImportTable(settings.HUDSizes or {})
Config.HUDProperties = settings.HUDProperties or {}
Config.CustomFrames = settings.CustomFrames or {}
HUD.LayoutsRemoved = {}
SaveConfig()
rebuildCustomFramesFromConfig()
applySavedPositions()
rebuildHUDOverlays()
updateHUDLayouts()
ApplyUIVisibility()
pcall(function() updateGUIColors() end)
end
table.insert(HUD.Connections, lockBtn.MouseButton1Click:Connect(function()
HUD.IsUnlocked = not HUD.IsUnlocked
lockBtn.Image = HUD.IsUnlocked and "rbxassetid://137042445663198" or "rbxassetid://137985778533954"
rebuildHUDOverlays()
pcall(function() updateGUIColors() end)
getgenv().Notify({
Title = "7yd7 | HUD Editor",
Content = HUD.IsUnlocked and "🔓 Interior Unlocked! Children are now editable." or "🔒 Interior Locked! Top-level only.",
Duration = 2
})
end))
rebuildHUDOverlays()
table.insert(HUD.Connections, exportBtn.MouseButton1Click:Connect(function()
local function normalizeExportTable(tbl)
if type(tbl) ~= "table" then return {} end
local out = {}
local allElems = getAllHUDObjects()
for eName, v in pairs(tbl) do
if type(v) == "table" and #v == 4 then
local sx, ox, sy, oy = v[1], v[2], v[3], v[4]
if ox ~= 0 or oy ~= 0 then
local el = allElems[eName]
local ps = el and el.Parent and el.Parent.AbsoluteSize
if ps and ps.X > 0 and ps.Y > 0 then
sx = sx + (ox / ps.X)
sy = sy + (oy / ps.Y)
end
end
out[eName] = {sx, 0, sy, 0}
else
out[eName] = v
end
end
return out
end
local function normalizeExportProps(props)
if type(props) ~= "table" then return {} end
local out = {}
local allElems = getAllHUDObjects()
for eName, p in pairs(props) do
local ep = {}
for k, v in pairs(p) do
if (k == "CornerRadius" or k == "Radius") and type(v) == "table" and #v == 2 then
local rs, ro = v[1], v[2]
if ro ~= 0 and rs == 0 then
local el = allElems[eName]
if el then
local minDim = math.min(el.AbsoluteSize.X, el.AbsoluteSize.Y)
if minDim > 0 then
rs = ro / minDim
ro = 0
end
end
end
ep[k] = {rs, ro}
else
ep[k] = v
end
end
out[eName] = ep
end
return out
end
local data = {
Type = "HUD",
Settings = {
HUDPositions = normalizeExportTable(Config.HUDPositions or {}),
HUDSizes = normalizeExportTable(Config.HUDSizes or {}),
HUDProperties = normalizeExportProps(Config.HUDProperties or {}),
CustomFrames = Config.CustomFrames or {}
}
}
setclipboard(HttpService:JSONEncode(data))
getgenv().Notify({ Title = "7yd7 | HUD Editor", Content = "✅ HUD settings copied", Duration = 2 })
end))
table.insert(HUD.Connections, importBtn.MouseButton1Click:Connect(function()
local popup, content = CreatePopup("Import HUD", UDim2.fromOffset(320, 240))
local popupRoot = HUD.SelectionGui or SettingsLib.UI
if popupRoot and popup.Parent ~= popupRoot then
popup.Parent = popupRoot
end
local baseZ = 7000
popup.ZIndex = baseZ
local backdrop = Instance.new("TextButton")
backdrop.Name = "HUDImportBackdrop"
backdrop.Parent = popup.Parent
backdrop.Size = UDim2.fromScale(1, 1)
backdrop.BackgroundTransparency = 1
backdrop.Text = ""
backdrop.AutoButtonColor = false
backdrop.ZIndex = baseZ - 1
backdrop.Active = true
local scroll = Instance.new("ScrollingFrame")
scroll.Parent = content
scroll.BackgroundTransparency = 1
scroll.BorderSizePixel = 0
scroll.Position = UDim2.new(0.05, 0, 0, 5)
scroll.Size = UDim2.new(0.9, 0, 0, 130)
scroll.CanvasSize = UDim2.new(0, 0, 0, 0)
scroll.AutomaticCanvasSize = Enum.AutomaticSize.Y
scroll.ScrollBarThickness = 4
scroll.Active = true
scroll.ScrollingEnabled = true
scroll.ScrollingDirection = Enum.ScrollingDirection.Y
scroll.ElasticBehavior = Enum.ElasticBehavior.WhenScrollable
local box = CreateInput(scroll, "Paste HUD JSON here...", "", true)
box.Size = UDim2.new(1, -8, 0, 130)
box.Position = UDim2.new(0, 0, 0, 0)
box.TextYAlignment = Enum.TextYAlignment.Top
box.ClearTextOnFocus = false
local function updateCanvas()
local padding = 8
local h = math.max(130, (box.TextBounds.Y or 0) + padding)
scroll.CanvasSize = UDim2.new(0, 0, 0, h)
end
box:GetPropertyChangedSignal("Text"):Connect(updateCanvas)
box:GetPropertyChangedSignal("TextBounds"):Connect(updateCanvas)
updateCanvas()
local imp = CreateButton(content, "IMPORT HUD", (State.EmoteTheme and State.EmoteTheme.Accent) or Color3.fromRGB(0, 255, 150), UDim2.new(0.05, 0, 0.8, 0), UDim2.new(0.9, 0, 0, 35))
imp.MouseButton1Click:Connect(function()
local s, d = pcall(function() return HttpService:JSONDecode(box.Text) end)
if s and type(d) == "table" then
local settings = d.Settings or d
if d.Type and d.Type ~= "HUD" then
getgenv().Notify({ Title = "Error", Content = "HUD import type mismatch!", Duration = 3 })
return
end
if type(settings) ~= "table" then
getgenv().Notify({ Title = "Error", Content = "Invalid HUD JSON", Duration = 3 })
return
end
applyHUDSettingsReplace(settings)
HUD.UndoStack = {}
if backdrop then backdrop:Destroy() end
popup:Destroy()
getgenv().Notify({ Title = "7yd7 | HUD Editor", Content = "✅ HUD settings imported", Duration = 2 })
else
getgenv().Notify({ Title = "Error", Content = "Invalid HUD JSON", Duration = 3 })
end
end)
local close = Instance.new("TextButton")
close.Size = UDim2.fromOffset(24, 24)
close.Position = UDim2.new(1, -30, 0, 5)
close.Text = "×"
close.Font = Enum.Font.GothamBold
close.TextSize = 20
close.BackgroundTransparency = 1
close.TextColor3 = Color3.new(1,1,1)
close.ZIndex = baseZ + 2
close.Active = true
close.AutoButtonColor = false
close.Parent = popup
close.MouseButton1Click:Connect(function()
if backdrop then backdrop:Destroy() end
popup:Destroy()
end)
backdrop.MouseButton1Click:Connect(function()
if backdrop then backdrop:Destroy() end
popup:Destroy()
end)
local function bumpPopupZIndex(panel, z)
if not panel then return end
panel.ZIndex = z
for _, d in ipairs(panel:GetDescendants()) do
if d:IsA("GuiObject") then
d.ZIndex = z + 1
end
end
end
bumpPopupZIndex(popup, baseZ)
close.ZIndex = baseZ + 2
end))
table.insert(HUD.Connections, backBtn.MouseButton1Click:Connect(function()
exitHUDEditor()
end))
table.insert(HUD.Connections, resetBtn.MouseButton1Click:Connect(function()
Config.HUDPositions = {}
Config.HUDSizes = {}
Config.CustomFrames = {}
Config.HUDProperties = {}
HUD.LayoutsRemoved = {}
SaveConfig()
local allElements = getAllHUDObjects()
for name, el in pairs(allElements) do
if name:match("^CustomFrame_") then
el:Destroy()
if UI.CustomFrames then UI.CustomFrames[name] = nil end
else
if HUD.DefaultPositions[name] then el.Position = HUD.DefaultPositions[name] end
if HUD.DefaultSizes[name] then el.Size = HUD.DefaultSizes[name] end
for internal, friendly in pairs(HUD.FriendlyNames) do
if name == friendly then
if internal:match("^Under%.") then
el.Parent = UI.Under
elseif internal:match("^Top%.") then
el.Parent = UI.Top
end
break
end
end
el.ZIndex = (name == "Top" or name == "Under") and 3 or (el:IsA("ImageButton") and 4 or 3)
if name == "Under" then
el.BackgroundTransparency = 1
else
el.BackgroundTransparency = (name == "Top" or name == "Reload" or name == "Changepage" or name == "EmoteWalkButton" or name == "SpeedBox" or name == "SpeedEmote" or name == "Favorite") and 0.4 or 1
end
if el:IsA("ImageButton") or el:IsA("ImageLabel") then
el.ImageTransparency = 0
end
if el:IsA("TextLabel") or el:IsA("TextBox") then
el.TextTransparency = 0.4
if HUD.DefaultTexts and HUD.DefaultTexts[name] then
el.Text = HUD.DefaultTexts[name]
end
if el:IsA("TextBox") and HUD.DefaultPlaceholders and HUD.DefaultPlaceholders[name] then
el.PlaceholderText = HUD.DefaultPlaceholders[name]
end
end
local cR = el:FindFirstChildWhichIsA("UICorner")
if cR then
cR.CornerRadius = UDim.new(0, 10)
end
end
end
pcall(function() updateGUIColors() end)
HUD.SelectedElement = nil
for _, h in pairs(HUD.ResizeHandles) do pcall(function() h:Destroy() end) end
HUD.ResizeHandles = {}
for _, c in pairs(HUD.ResizeConnections) do pcall(function() c:Disconnect() end) end
HUD.ResizeConnections = {}
rebuildHUDOverlays()
updateHUDLayouts()
ApplyUIVisibility()
State.totalPages = calculateTotalPages()
if State.currentPage > State.totalPages then
State.currentPage = State.totalPages
end
updatePageDisplay()
getgenv().Notify({ Title = "7yd7 | HUD Editor", Content = "🔄 All designs and frames have been fully reset", Duration = 3 })
end))
local propertiesPanel = Instance.new("Frame")
propertiesPanel.Name = "HUDPropertiesPanel"
propertiesPanel.Parent = overlay
propertiesPanel.BackgroundColor3 = Color3.fromRGB(0, 0, 0)
propertiesPanel.BackgroundTransparency = 0.4
propertiesPanel.Size = UDim2.fromOffset(260, 150)
propertiesPanel.AnchorPoint = Vector2.new(1, 0)
propertiesPanel.Position = UDim2.new(1, -10, 0, 60)
propertiesPanel.Visible = false
propertiesPanel.ZIndex = 6005
propertiesPanel.ClipsDescendants = true
local panelCorner = Instance.new("UICorner")
panelCorner.CornerRadius = UDim.new(0, 10)
panelCorner.Parent = propertiesPanel
local title = Instance.new("TextLabel")
title.Parent = propertiesPanel
title.BackgroundTransparency = 1
title.Size = UDim2.new(1, 0, 0, 26)
title.Position = UDim2.new(0, 0, 0, 2)
title.Font = Enum.Font.SourceSansBold
title.Text = "No Element"
title.TextColor3 = Color3.fromRGB(255, 255, 255)
title.TextSize = 14
title.TextScaled = true
title.ZIndex = 6006
local propContent = Instance.new("ScrollingFrame")
propContent.Parent = propertiesPanel
propContent.BackgroundTransparency = 1
propContent.Position = UDim2.new(0, 0, 0, 28)
propContent.Size = UDim2.new(1, 0, 1, -32)
propContent.CanvasSize = UDim2.new(0, 0, 0, 0)
propContent.ScrollBarThickness = 2
propContent.Active = true
propContent.ScrollingEnabled = true
propContent.ZIndex = 6006
local propLayout = Instance.new("UIListLayout")
propLayout.Parent = propContent
propLayout.SortOrder = Enum.SortOrder.LayoutOrder
propLayout.Padding = UDim.new(0, 6)
propLayout.HorizontalAlignment = Enum.HorizontalAlignment.Center
HUD.LastTouchedElement = nil
HUD.LastTouchedName = nil
local function createPropRow(label, lOrder, isLarge)
local row = Instance.new("Frame")
row.BackgroundTransparency = 1
row.Size = UDim2.new(0.92, 0, 0, isLarge and 50 or 26)
row.LayoutOrder = lOrder
row.ZIndex = 6006
row.Parent = propContent
local lbl = Instance.new("TextLabel")
lbl.Parent = row
lbl.Size = UDim2.new(0, 70, 0, 26)
lbl.BackgroundTransparency = 1
lbl.Text = label
lbl.TextColor3 = Color3.fromRGB(180, 180, 180)
lbl.TextXAlignment = Enum.TextXAlignment.Left
lbl.Font = Enum.Font.SourceSansBold
lbl.TextSize = 12
lbl.ZIndex = 6007
local tbox = Instance.new("TextBox")
tbox.Parent = row
tbox.Size = UDim2.new(1, -75, 1, -4)
tbox.Position = UDim2.new(0, 75, 0, 2)
tbox.BackgroundColor3 = Color3.fromRGB(30, 30, 30)
tbox.BackgroundTransparency = 0.3
tbox.TextColor3 = Color3.fromRGB(255, 255, 255)
tbox.Font = Enum.Font.Code
tbox.TextSize = 12
tbox.TextXAlignment = isLarge and Enum.TextXAlignment.Left or Enum.TextXAlignment.Center
tbox.TextYAlignment = isLarge and Enum.TextYAlignment.Top or Enum.TextYAlignment.Center
tbox.ClearTextOnFocus = false
tbox.TextWrapped = isLarge
tbox.PlaceholderText = ""
tbox.PlaceholderColor3 = Color3.fromRGB(80, 80, 80)
tbox.ZIndex = 6007
local tc = Instance.new("UICorner"); tc.CornerRadius = UDim.new(0, 6); tc.Parent = tbox
return row, tbox
end
local _, posBox = createPropRow("Position", 1)
local _, sizeBox = createPropRow("Size", 2)
local zRow, zBox = createPropRow("ZIndex", 3)
local bgRow, bgBox = createPropRow("BgTrans", 4)
local bgcRow, bgcBox = createPropRow("BgColor", 5)
local imgRow, imgBox = createPropRow("ImgTrans", 6)
local imgcRow, imgcBox = createPropRow("ImgColor", 7)
local radRow, radBox = createPropRow("Radius", 8)
local txtRow, txtBox = createPropRow("Text", 9, true)
local phRow, phBox = createPropRow("Placeholder", 10, true)
local ttrRow, ttrBox = createPropRow("TxtTrans", 11)
local txtcRow, txtcBox = createPropRow("TxtColor", 12)
local deleteRow = Instance.new("Frame")
deleteRow.BackgroundTransparency = 1
deleteRow.Size = UDim2.new(0.92, 0, 0, 28)
deleteRow.LayoutOrder = 13
deleteRow.ZIndex = 6006
deleteRow.Parent = propContent
local deleteBtn = Instance.new("TextButton")
deleteBtn.Parent = deleteRow
deleteBtn.Size = UDim2.new(1, 0, 1, 0)
deleteBtn.BackgroundColor3 = Color3.fromRGB(170, 60, 60)
deleteBtn.BackgroundTransparency = 0.1
deleteBtn.TextColor3 = Color3.fromRGB(255, 255, 255)
deleteBtn.Font = Enum.Font.GothamBold
deleteBtn.TextSize = 12
deleteBtn.Text = "Delete Custom Frame"
deleteBtn.ZIndex = 6007
local delCorner = Instance.new("UICorner"); delCorner.CornerRadius = UDim.new(0, 6); delCorner.Parent = deleteBtn
local function parseUDim2(text)
local s1, o1, s2, o2 = text:match("{%s*([%d%.%-]+)%s*,%s*([%d%.%-]+)%s*}%s*,%s*{%s*([%d%.%-]+)%s*,%s*([%d%.%-]+)%s*}")
if s1 and o1 and s2 and o2 then
return tonumber(s1), tonumber(o1), tonumber(s2), tonumber(o2)
end
local a, b = text:match("([%d%.%-]+)%s*,%s*([%d%.%-]+)")
if a and b then
local va, vb = tonumber(a), tonumber(b)
if va and vb then
return 0, va, 0, vb
end
end
return nil
end
local function formatUDim2(udim)
return string.format("{%g, %g},{%g, %g}", udim.X.Scale, udim.X.Offset, udim.Y.Scale, udim.Y.Offset)
end
table.insert(HUD.Connections, propertiesBtn.MouseButton1Click:Connect(function()
propertiesPanel.Visible = not propertiesPanel.Visible
end))
local function formatUDim(udim)
return string.format("{%g, %g}", udim.Scale, udim.Offset)
end
local function formatRGB(c)
return string.format("%d, %d, %d", math.floor(c.R * 255 + 0.5), math.floor(c.G * 255 + 0.5), math.floor(c.B * 255 + 0.5))
end
local function parseRGB(text)
local a, b, c = text:match("([%d%.%-]+)%s*,%s*([%d%.%-]+)%s*,%s*([%d%.%-]+)")
if not a then return nil end
local r, g, b2 = tonumber(a), tonumber(b), tonumber(c)
if not r or not g or not b2 then return nil end
local maxv = math.max(r, g, b2)
if maxv <= 1 then
r, g, b2 = r * 255, g * 255, b2 * 255
end
r = math.clamp(r, 0, 255)
g = math.clamp(g, 0, 255)
b2 = math.clamp(b2, 0, 255)
return r, g, b2
end
table.insert(HUD.Connections, RunService.RenderStepped:Connect(function()
if not propertiesPanel.Visible then return end
local e = HUD.LastTouchedElement
local eName = HUD.LastTouchedName
if e and e.Parent then
title.Text = string.format("[%s] %s", e.ClassName, eName or "Unknown")
if not posBox:IsFocused() then posBox.Text = formatUDim2(e.Position) end
if not sizeBox:IsFocused() then sizeBox.Text = formatUDim2(e.Size) end
zRow.Visible = true
if not zBox:IsFocused() then zBox.Text = tostring(e.ZIndex) end
bgRow.Visible = true
if not bgBox:IsFocused() then bgBox.Text = tostring(math.floor(e.BackgroundTransparency * 100) / 100) end
if e:IsA("ImageLabel") or e:IsA("ImageButton") then
imgRow.Visible = true
if not imgBox:IsFocused() then imgBox.Text = tostring(math.floor(e.ImageTransparency * 100) / 100) end
else
imgRow.Visible = false
end
bgcRow.Visible = true
if not bgcBox:IsFocused() then bgcBox.Text = formatRGB(e.BackgroundColor3) end
if e:IsA("ImageLabel") or e:IsA("ImageButton") then
imgcRow.Visible = true
if not imgcBox:IsFocused() then imgcBox.Text = formatRGB(e.ImageColor3) end
else
imgcRow.Visible = false
end
if e:IsA("TextLabel") or e:IsA("TextBox") then
ttrRow.Visible = true
if not ttrBox:IsFocused() then ttrBox.Text = tostring(math.floor(e.TextTransparency * 100) / 100) end
txtRow.Visible = true
if not txtBox:IsFocused() then txtBox.Text = e.Text end
txtcRow.Visible = true
if not txtcBox:IsFocused() then txtcBox.Text = formatRGB(e.TextColor3) end
if e:IsA("TextBox") then
phRow.Visible = true
if not phBox:IsFocused() then phBox.Text = e.PlaceholderText end
else
phRow.Visible = false
end
else
ttrRow.Visible = false
txtRow.Visible = false
phRow.Visible = false
txtcRow.Visible = false
end
deleteRow.Visible = (eName and eName:match("^CustomFrame_")) and true or false
local cR = e:FindFirstChildWhichIsA("UICorner")
if cR then
radRow.Visible = true
if not radBox:IsFocused() then radBox.Text = formatUDim(cR.CornerRadius) end
else
radRow.Visible = false
end
else
title.Text = "No Element Selected"
zRow.Visible = false
bgRow.Visible = false
imgRow.Visible = false
bgcRow.Visible = false
imgcRow.Visible = false
radRow.Visible = false
ttrRow.Visible = false
txtRow.Visible = false
phRow.Visible = false
txtcRow.Visible = false
deleteRow.Visible = false
if not posBox:IsFocused() then posBox.Text = "" end
if not sizeBox:IsFocused() then sizeBox.Text = "" end
end
local totalH = propLayout.AbsoluteContentSize.Y + 10
propContent.CanvasSize = UDim2.new(0, 0, 0, totalH)
local vpY = workspace.CurrentCamera and workspace.CurrentCamera.ViewportSize.Y or 800
local maxH = math.floor(vpY * 0.55)
propertiesPanel.Size = UDim2.fromOffset(260, math.min(maxH, totalH + 40))
end))
local function saveHUDProp(eName, propKey, val)
if not Config.HUDProperties then Config.HUDProperties = {} end
if not Config.HUDProperties[eName] then Config.HUDProperties[eName] = {} end
Config.HUDProperties[eName][propKey] = val
SaveConfig()
end
table.insert(HUD.Connections, deleteBtn.MouseButton1Click:Connect(function()
local eName = HUD.LastTouchedName
if not eName or not eName:match("^CustomFrame_") then return end
local frame = UI.CustomFrames and UI.CustomFrames[eName]
if frame and frame.Parent then frame:Destroy() end
if UI.CustomFrames then UI.CustomFrames[eName] = nil end
if Config.CustomFrames then Config.CustomFrames[eName] = nil end
if Config.HUDPositions then Config.HUDPositions[eName] = nil end
if Config.HUDSizes then Config.HUDSizes[eName] = nil end
if Config.HUDProperties then Config.HUDProperties[eName] = nil end
if HUD.DefaultPositions then HUD.DefaultPositions[eName] = nil end
if HUD.DefaultSizes then HUD.DefaultSizes[eName] = nil end
if HUD.DefaultTexts then HUD.DefaultTexts[eName] = nil end
if HUD.DefaultPlaceholders then HUD.DefaultPlaceholders[eName] = nil end
SaveConfig()
HUD.SelectedElement = nil
HUD.LastTouchedElement = nil
HUD.LastTouchedName = nil
for _, h in pairs(HUD.ResizeHandles) do pcall(function() h:Destroy() end) end
HUD.ResizeHandles = {}
for _, c in pairs(HUD.ResizeConnections) do pcall(function() c:Disconnect() end) end
HUD.ResizeConnections = {}
rebuildHUDOverlays()
updateHUDLayouts()
ApplyUIVisibility()
pcall(function() updateGUIColors() end)
getgenv().Notify({ Title = "7yd7 | HUD Editor", Content = "🗑️ Custom Frame deleted", Duration = 2 })
end))
table.insert(HUD.Connections, posBox.FocusLost:Connect(function()
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
local s1, o1, s2, o2 = parseUDim2(posBox.Text)
if s1 then
local prev = captureHUDState(eName, e)
e.Position = UDim2.new(s1, o1, s2, o2)
if prev and not sameUDim2(prev.pos, e.Position) then
pushUndo(prev)
end
Config.HUDPositions[eName] = {s1, o1, s2, o2}
end
end))
table.insert(HUD.Connections, sizeBox.FocusLost:Connect(function()
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
local s1, o1, s2, o2 = parseUDim2(sizeBox.Text)
if s1 then
local prev = captureHUDState(eName, e)
e.Size = UDim2.new(s1, o1, s2, o2)
if prev and not sameUDim2(prev.size, e.Size) then
pushUndo(prev)
end
if not Config.HUDSizes then Config.HUDSizes = {} end
Config.HUDSizes[eName] = {s1, o1, s2, o2}
end
end))
table.insert(HUD.Connections, zBox.FocusLost:Connect(function()
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
local v = tonumber(zBox.Text)
if v then
local prev = captureHUDState(eName, e)
e.ZIndex = v
if prev and prev.z ~= e.ZIndex then
pushUndo(prev)
end
saveHUDProp(eName, "ZIndex", v)
end
end))
table.insert(HUD.Connections, bgBox.FocusLost:Connect(function()
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
local v = tonumber(bgBox.Text)
if v then
local prev = captureHUDState(eName, e)
e.BackgroundTransparency = math.clamp(v, 0, 1)
if prev and prev.bgTrans ~= e.BackgroundTransparency then
pushUndo(prev)
end
saveHUDProp(eName, "BgTrans", e.BackgroundTransparency)
end
end))
table.insert(HUD.Connections, imgBox.FocusLost:Connect(function()
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
local v = tonumber(imgBox.Text)
if v and (e:IsA("ImageLabel") or e:IsA("ImageButton")) then
local prev = captureHUDState(eName, e)
e.ImageTransparency = math.clamp(v, 0, 1)
if prev and prev.imgTrans ~= e.ImageTransparency then
pushUndo(prev)
end
saveHUDProp(eName, "ImgTrans", e.ImageTransparency)
end
end))
table.insert(HUD.Connections, bgcBox.FocusLost:Connect(function()
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
local r, g, b = parseRGB(bgcBox.Text)
if r then
if isThemeDefaultRGB(r, g, b) then
if Config.HUDProperties and Config.HUDProperties[eName] then
Config.HUDProperties[eName].BgColor = nil
if next(Config.HUDProperties[eName]) == nil then
Config.HUDProperties[eName] = nil
end
SaveConfig()
end
pcall(function() updateGUIColors() end)
return
end
local prev = captureHUDState(eName, e)
local c = Color3.fromRGB(r, g, b)
pcall(function() e.BackgroundColor3 = c end)
if prev and not sameColor(prev.bgColor, e.BackgroundColor3) then
pushUndo(prev)
end
saveHUDProp(eName, "BgColor", {r, g, b})
end
end))
table.insert(HUD.Connections, imgcBox.FocusLost:Connect(function()
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
if not (e:IsA("ImageLabel") or e:IsA("ImageButton")) then return end
local r, g, b = parseRGB(imgcBox.Text)
if r then
if isThemeDefaultRGB(r, g, b) then
if Config.HUDProperties and Config.HUDProperties[eName] then
Config.HUDProperties[eName].ImgColor = nil
if next(Config.HUDProperties[eName]) == nil then
Config.HUDProperties[eName] = nil
end
SaveConfig()
end
pcall(function() updateGUIColors() end)
return
end
local prev = captureHUDState(eName, e)
local c = Color3.fromRGB(r, g, b)
pcall(function() e.ImageColor3 = c end)
if prev and prev.imgColor and not sameColor(prev.imgColor, e.ImageColor3) then
pushUndo(prev)
end
saveHUDProp(eName, "ImgColor", {r, g, b})
end
end))
table.insert(HUD.Connections, radBox.FocusLost:Connect(function(enter)
if not enter then return end
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
local a, b = radBox.Text:match("{%s*([%d%.%-]+)%s*,%s*([%d%.%-]+)%s*}")
if not a and not b then a, b = radBox.Text:match("([%d%.%-]+)%s*,%s*([%d%.%-]+)") end
if a and b then
local va, vb = tonumber(a), tonumber(b)
if va and vb then
local cR = e:FindFirstChildWhichIsA("UICorner")
if cR then
local prev = captureHUDState(eName, e)
if vb ~= 0 and va == 0 then
local minDim = math.min(e.AbsoluteSize.X, e.AbsoluteSize.Y)
if minDim > 0 then
va = vb / minDim
vb = 0
end
end
cR.CornerRadius = UDim.new(va, vb)
if prev and prev.radius and not sameUDim(prev.radius, cR.CornerRadius) then
pushUndo(prev)
end
saveHUDProp(eName, "CornerRadius", {va, vb})
end
end
end
end))
table.insert(HUD.Connections, txtBox.FocusLost:Connect(function(enter)
if not enter then return end
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
if e:IsA("TextLabel") or e:IsA("TextBox") then
local prev = captureHUDState(eName, e)
e.Text = txtBox.Text
if prev and prev.text ~= e.Text then
pushUndo(prev)
end
saveHUDProp(eName, "Text", txtBox.Text)
end
end))
table.insert(HUD.Connections, phBox.FocusLost:Connect(function(enter)
if not enter then return end
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
if e:IsA("TextBox") then
local prev = captureHUDState(eName, e)
e.PlaceholderText = phBox.Text
if prev and prev.placeholder ~= e.PlaceholderText then
pushUndo(prev)
end
saveHUDProp(eName, "PlaceholderText", phBox.Text)
end
end))
table.insert(HUD.Connections, ttrBox.FocusLost:Connect(function(enter)
if not enter then return end
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
local v = tonumber(ttrBox.Text)
if v and (e:IsA("TextLabel") or e:IsA("TextBox")) then
local prev = captureHUDState(eName, e)
e.TextTransparency = math.clamp(v, 0, 1)
if prev and prev.textTrans ~= e.TextTransparency then
pushUndo(prev)
end
saveHUDProp(eName, "TextTransparency", e.TextTransparency)
end
end))
table.insert(HUD.Connections, txtcBox.FocusLost:Connect(function()
local e, eName = HUD.LastTouchedElement, HUD.LastTouchedName
if not e or not e.Parent or not eName then return end
if not (e:IsA("TextLabel") or e:IsA("TextBox")) then return end
local r, g, b = parseRGB(txtcBox.Text)
if r then
if isThemeDefaultRGB(r, g, b) then
if Config.HUDProperties and Config.HUDProperties[eName] then
Config.HUDProperties[eName].TxtColor = nil
if next(Config.HUDProperties[eName]) == nil then
Config.HUDProperties[eName] = nil
end
SaveConfig()
end
pcall(function() updateGUIColors() end)
return
end
local prev = captureHUDState(eName, e)
local c = Color3.fromRGB(r, g, b)
pcall(function() e.TextColor3 = c end)
if prev and prev.textColor and not sameColor(prev.textColor, e.TextColor3) then
pushUndo(prev)
end
saveHUDProp(eName, "TxtColor", {r, g, b})
end
end))
if UI.Search then UI.Search.TextEditable = false; UI.Search.Active = false; pcall(function() UI.Search:ReleaseFocus() end) end
if UI.SpeedBox then UI.SpeedBox.TextEditable = false; UI.SpeedBox.Active = false; pcall(function() UI.SpeedBox:ReleaseFocus() end) end
if UI._2Routenumber then UI._2Routenumber.TextEditable = false; UI._2Routenumber.Active = false; pcall(function() UI._2Routenumber:ReleaseFocus() end) end
local allMovable = getMovableElements()
local snapGuideH = Instance.new("Frame")
snapGuideH.Name = "SnapGuide"
snapGuideH.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
snapGuideH.BorderSizePixel = 0
snapGuideH.Size = UDim2.new(1, 0, 0, 1)
snapGuideH.ZIndex = 6002
snapGuideH.Visible = false
snapGuideH.Parent = overlay
local snapGuideV = Instance.new("Frame")
snapGuideV.Name = "SnapGuide"
snapGuideV.BackgroundColor3 = Color3.fromRGB(0, 170, 255)
snapGuideV.BorderSizePixel = 0
snapGuideV.Size = UDim2.new(0, 1, 1, 0)
snapGuideV.ZIndex = 6002
snapGuideV.Visible = false
snapGuideV.Parent = overlay
for name, element in pairs(allMovable) do
setupElementDragging(name, element, getMovableElements(), snapGuideV, snapGuideH)
end
table.insert(HUD.Connections, addBtn.MouseButton1Click:Connect(function()
local nameIndex = 1
while UI.CustomFrames and UI.CustomFrames["CustomFrame_"..nameIndex] do
nameIndex = nameIndex + 1
end
local newName = "CustomFrame_"..nameIndex
local _, emotesWheel = checkEmotesMenuExists()
local cf = Instance.new("Frame")
cf.Name = newName
cf.Parent = emotesWheel
cf.BackgroundTransparency = 0.4
cf.ZIndex = 3
cf.BorderSizePixel = 0
cf.Active = true
cf.Size = UDim2.new(0.3, 0, 0.3, 0)
cf.Position = UDim2.new(0.5, 0, 0.5, 0)
local corner = Instance.new("UICorner")
corner.CornerRadius = UDim.new(0, 10)
corner.Parent = cf
if not UI.CustomFrames then UI.CustomFrames = {} end
UI.CustomFrames[newName] = cf
HUD.DefaultSizes[newName] = UDim2.new(0.3, 0, 0.3, 0)
HUD.DefaultPositions[newName] = UDim2.new(0.5, 0, 0.5, 0)
Config.HUDPositions[newName] = {0.5, 0, 0.5, 0}
if not Config.HUDSizes then Config.HUDSizes = {} end
Config.HUDSizes[newName] = {0.3, 0, 0.3, 0}
if not Config.CustomFrames then Config.CustomFrames = {} end
Config.CustomFrames[newName] = {ZIndex = 3}
pcall(function() updateGUIColors() end)
setupElementDragging(newName, cf, getMovableElements(), snapGuideV, snapGuideH)
selectHUDElement(newName, cf)
getgenv().Notify({ Title = "7yd7 | HUD Editor", Content = "➕ Custom Frame added!", Duration = 2 })
end))
getgenv().Notify({ Title = "7yd7 | HUD Editor", Content = "✏️ Drag elements to reposition", Duration = 5 })
end
State.RefreshUI = function()
State.totalPages = calculateTotalPages()
updatePageDisplay()
if State.currentMode == "animation" then
updateAnimations()
else
updateEmotes()
end
end
State.RefreshSettingsUI = function()
if TogglesUI then
for key, toggle in pairs(TogglesUI) do
if Config[key] ~= nil and toggle.SetState then
toggle.SetState(Config[key])
end
end
end
end
function checkAndRecreateGUI()
local exists, emotesWheel = checkEmotesMenuExists()
if not exists then
State.isGUICreated = false
return
end
if not emotesWheel:FindFirstChild("Under") or not emotesWheel:FindFirstChild("Top") or
not emotesWheel:FindFirstChild("EmoteWalkButton") or not emotesWheel:FindFirstChild("Favorite") or
not emotesWheel:FindFirstChild("SpeedEmote") or not emotesWheel:FindFirstChild("SpeedBox") or
not emotesWheel:FindFirstChild("Changepage") or not emotesWheel:FindFirstChild("Reload") then
State.isGUICreated = false
if createGUIElements() then
updatePageDisplay()
updateEmotes()
loadSpeedEmoteConfig()
end
end
end
if player.Character then
onCharacterAdded(player.Character)
end
player.CharacterAdded:Connect(function(char)
character = char
humanoid = char:WaitForChild("Humanoid")
onCharacterAdded(char)
task.spawn(function()
local attempts = 0
while attempts < 20 do
if checkEmotesMenuExists() then
task.wait(0.2)
if createGUIElements() then
updatePageDisplay()
updateEmotes()
updateGUIColors()
loadSpeedEmoteConfig()
end
break
end
attempts = attempts + 1
task.wait(0.1)
end
end)
end)
RunService.Heartbeat:Connect(function()
if not State.isGUICreated then
checkAndRecreateGUI()
else
updateGUIColors()
enforceImages()
end
end)
RunService.Stepped:Connect(function()
if humanoid and State.currentEmoteTrack and typeof(State.currentEmoteTrack) == "Instance" and State.currentEmoteTrack:IsA("AnimationTrack") and State.currentEmoteTrack.IsPlaying then
if humanoid.MoveDirection.Magnitude > 0 then
if State.speedEmoteEnabled and not State.emotesWalkEnabled then
State.currentEmoteTrack:Stop()
State.currentEmoteTrack = nil
end
end
end
end)
task.spawn(function()
loadFavoritesAnimations()
fetchAllEmotes()
loadSpeedEmoteConfig()
end)
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.Chat, true)
task.spawn(function()
while true do
local robloxGui = game:GetService("CoreGui"):FindFirstChild("RobloxGui")
local emotesMenu = robloxGui and robloxGui:FindFirstChild("EmotesMenu")
if not emotesMenu then
StarterGui:SetCoreGuiEnabled(Enum.CoreGuiType.EmotesMenu, true)
else
local exists = emotesMenu:FindFirstChild("Children") and emotesMenu.Children:FindFirstChild("Main") and
emotesMenu.Children.Main:FindFirstChild("EmotesWheel")
if exists then
local emotesWheel = emotesMenu.Children.Main.EmotesWheel
if not emotesWheel:FindFirstChild("Under") or not emotesWheel:FindFirstChild("Top") then
if createGUIElements then
createGUIElements()
loadSpeedEmoteConfig()
end
updateGUIColors()
updatePageDisplay()
end
end
end
task.wait(0.3)
end
end)
if UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled then
SafeLoad("https://raw.githubusercontent.com/7yd7/Hub/refs/heads/Branch/GUIS/OpenEmote.lua", "Open Emote")
getgenv().Notify({
Title = '7yd7 | Emote Mobile',
Content = '📱 Added emote open button for ease of use',
Duration = 10
})
end
if UserInputService.KeyboardEnabled then
getgenv().Notify({
Title = '7yd7 | Emote PC',
Content = '💻 Open menu press button "."',
Duration = 10
})
end