--[[ ================================================================================ ALibRoblox — GUI Library for Roblox (Executor / Studio) Version: 1.0.0 USAGE EXAMPLE (uncomment and run after loading the library): local Library = loadstring(game:HttpGet( "https://raw.githubusercontent.com/GRYurv/Lib-GUI-Roblox/main/Library.lua" ))() Library:SetLanguage("ru") Library:CreateTheme({ name = "Ocean", accentColor = Color3.fromRGB(0, 200, 255), accentColor2 = Color3.fromRGB(0, 120, 200), backgroundColor = Color3.fromRGB(5, 15, 30), }) local Window = Library:CreateWindow({ title = "ALib Demo", name = "ALibDemo", theme = "Ocean", size = Vector2.new(560, 440), }) local Main = Window:AddTab("Главная", "🏠") local Combat = Window:AddTab("Бой", "rbxassetid://6034509993") local Visual = Window:AddTab("Визуал", "👁") local sec = Main:AddSection("Основное") sec:AddButton("Привет", function() Library:Notification("Успех", "Кнопка нажата!", 3, "success") end, { tooltip = "Нажми меня", description = "demo button" }) local esp = sec:AddToggle("ESP", false, function(v) print("ESP:", v) end, { description = "wallhack esp" }) sec:AddSlider("FOV", 60, 120, 90, function(v) print("FOV:", v) end) sec:AddDropdown("Режим", {"Legit", "Rage", "Silent"}, "Legit", function(v) print(v) end) sec:AddColorpicker("Цвет", Color3.fromRGB(255, 80, 80), function(c) print(c) end) sec:AddBind("Аим", Enum.KeyCode.E, function(v) print("Hold:", v) end, { mode = "hold", tooltip = "Удерживай E" }) sec:AddLabel("Статус: OK") sec:AddParagraph("Инфо", "Демонстрация библиотеки ALibRoblox.") local sec2 = Combat:AddSection("Аим") sec2:AddToggle("Silent Aim", false, function(v) end, { flag = "Silent_Enabled" }) sec2:AddBind("Toggle Aim", Enum.KeyCode.X, function(k) print(k) end, { mode = "toggle" }) Library:CreateWatermark("ALib Demo", { showFps = true, showTime = true, position = "top-right" }) Library:LoadConfig() Window:Build() Library:Notification("Инфо", "Библиотека загружена", 3, "info") Library:Notification("Успех", "Всё работает!", 3, "success") Library:Notification("Внимание", "Проверьте настройки", 3, "warning") Library:Notification("Ошибка", "Пример ошибки", 3, "error") -- RightShift скрывает/показывает меню (см. inject.lua) ================================================================================ ]] local VERSION = "1.0.1" local Players = game:GetService("Players") local TweenService = game:GetService("TweenService") local TextService = game:GetService("TextService") local UserInputService = game:GetService("UserInputService") local RunService = game:GetService("RunService") local HttpService = game:GetService("HttpService") -- ─── Constants ─────────────────────────────────────────────────────────────── local MAIN_CORNER = 16 local ELEMENT_HEIGHT = 42 local TITLE_HEIGHT = 52 local SEARCH_HEIGHT = 32 local TAB_BAR_HEIGHT = 40 local NOTIFY_WIDTH = 320 local NOTIFY_MARGIN = 16 local MIN_TOUCH = 36 local MIN_WINDOW_SIZE = Vector2.new(400, 300) local DEFAULT_WINDOW_SIZE = Vector2.new(560, 440) local CONFIG_FOLDER = "ALibRoblox" local CONFIG_FILE = CONFIG_FOLDER .. "/config.json" local TWEEN_FAST = TweenInfo.new(0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.Out) local TWEEN_OPEN = TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out) local TWEEN_TAB = TweenInfo.new(0.25, Enum.EasingStyle.Quint, Enum.EasingDirection.Out) local TWEEN_WINDOW = TweenInfo.new(0.22, Enum.EasingStyle.Back, Enum.EasingDirection.Out) -- ─── Builtin Themes ────────────────────────────────────────────────────────── local BUILTIN_THEMES = { Dark = { name = "Dark", backgroundColor = Color3.fromRGB(10, 12, 18), backgroundColor2 = Color3.fromRGB(18, 22, 32), tabBarColor = Color3.fromRGB(14, 16, 24), contentColor = Color3.fromRGB(16, 18, 26), accentColor = Color3.fromRGB(79, 139, 255), accentColor2 = Color3.fromRGB(120, 90, 255), textColor = Color3.fromRGB(245, 247, 255), subTextColor = Color3.fromRGB(140, 148, 170), strokeColor = Color3.fromRGB(45, 52, 72), elementColor = Color3.fromRGB(24, 28, 40), hoverColor = Color3.fromRGB(34, 40, 58), knobColor = Color3.fromRGB(255, 255, 255), buttonTextColor = Color3.fromRGB(255, 255, 255), toggleOnColor = Color3.fromRGB(79, 139, 255), toggleOffColor = Color3.fromRGB(45, 52, 72), searchBarColor = Color3.fromRGB(20, 24, 36), tooltipColor = Color3.fromRGB(30, 34, 48), cornerRadius = 10, elementHeight = ELEMENT_HEIGHT, }, Light = { name = "Light", backgroundColor = Color3.fromRGB(248, 249, 252), backgroundColor2 = Color3.fromRGB(235, 238, 248), tabBarColor = Color3.fromRGB(240, 242, 250), contentColor = Color3.fromRGB(252, 253, 255), accentColor = Color3.fromRGB(59, 110, 240), accentColor2 = Color3.fromRGB(99, 130, 255), textColor = Color3.fromRGB(22, 26, 38), subTextColor = Color3.fromRGB(110, 118, 140), strokeColor = Color3.fromRGB(210, 216, 230), elementColor = Color3.fromRGB(228, 232, 242), hoverColor = Color3.fromRGB(215, 222, 238), knobColor = Color3.fromRGB(255, 255, 255), buttonTextColor = Color3.fromRGB(255, 255, 255), toggleOnColor = Color3.fromRGB(59, 110, 240), toggleOffColor = Color3.fromRGB(210, 216, 230), searchBarColor = Color3.fromRGB(235, 238, 248), tooltipColor = Color3.fromRGB(220, 224, 235), cornerRadius = 10, elementHeight = ELEMENT_HEIGHT, }, Neon = { name = "Neon", backgroundColor = Color3.fromRGB(8, 10, 28), backgroundColor2 = Color3.fromRGB(16, 12, 42), tabBarColor = Color3.fromRGB(10, 8, 32), contentColor = Color3.fromRGB(14, 12, 36), accentColor = Color3.fromRGB(0, 255, 220), accentColor2 = Color3.fromRGB(180, 60, 255), textColor = Color3.fromRGB(255, 255, 255), subTextColor = Color3.fromRGB(160, 190, 255), strokeColor = Color3.fromRGB(0, 140, 180), elementColor = Color3.fromRGB(22, 18, 52), hoverColor = Color3.fromRGB(32, 26, 72), knobColor = Color3.fromRGB(255, 255, 255), buttonTextColor = Color3.fromRGB(255, 255, 255), toggleOnColor = Color3.fromRGB(0, 255, 220), toggleOffColor = Color3.fromRGB(0, 80, 100), searchBarColor = Color3.fromRGB(14, 12, 36), tooltipColor = Color3.fromRGB(22, 18, 52), cornerRadius = 12, elementHeight = ELEMENT_HEIGHT, }, } local NOTIFY_COLORS = { success = Color3.fromRGB(46, 204, 113), info = Color3.fromRGB(52, 152, 219), warning = Color3.fromRGB(241, 196, 15), error = Color3.fromRGB(231, 76, 60), } local NOTIFY_ICONS = { success = "✓", info = "ℹ", warning = "⚠", error = "✕", } -- ─── I18n ──────────────────────────────────────────────────────────────────── local LANGUAGES = { en = { close = "Close", minimize = "Minimize", search_placeholder = "Search...", settings = "Settings", theme = "Theme", reset_theme = "Reset Theme", theme_editor = "Theme Editor", press_key = "Press a key...", none = "None", bind_toggle = "Toggle", bind_hold = "Hold", notify_success = "Success", notify_info = "Info", notify_warning = "Warning", notify_error = "Error", fps = "FPS", time = "Time", appearance = "Appearance & preferences", }, ru = { close = "Закрыть", minimize = "Свернуть", search_placeholder = "Поиск...", settings = "Настройки", theme = "Тема", reset_theme = "Сбросить тему", theme_editor = "Редактор темы", press_key = "Нажмите клавишу...", none = "Нет", bind_toggle = "Переключение", bind_hold = "Удержание", notify_success = "Успех", notify_info = "Информация", notify_warning = "Внимание", notify_error = "Ошибка", fps = "FPS", time = "Время", appearance = "Внешний вид и настройки", }, } -- ─── Library Singleton ─────────────────────────────────────────────────────── local Library = { Version = VERSION, Themes = BUILTIN_THEMES, _flags = {}, _elements = {}, _windows = {}, _connections = {}, _destroyed = false, _currentLanguage = "ru", _currentTheme = "Dark", _activeWindow = nil, _notifyQueue = {}, _notifyShowing = false, _watermark = nil, _configPath = CONFIG_FILE, } -- ─── Utilities ─────────────────────────────────────────────────────────────── local function deepCopy(tbl) local copy = {} for k, v in pairs(tbl) do copy[k] = type(v) == "table" and deepCopy(v) or v end return copy end local function tween(inst, props, info) return TweenService:Create(inst, info or TWEEN_FAST, props) end local function addCorner(parent, radius) local c = Instance.new("UICorner") c.CornerRadius = UDim.new(0, radius or 8) c.Parent = parent return c end local function addPadding(parent, top, bottom, left, right) local p = Instance.new("UIPadding") p.PaddingTop = UDim.new(0, top or 8) p.PaddingBottom = UDim.new(0, bottom or 8) p.PaddingLeft = UDim.new(0, left or 12) p.PaddingRight = UDim.new(0, right or 12) p.Parent = parent return p end local function addList(parent, padding, direction) local l = Instance.new("UIListLayout") l.Padding = UDim.new(0, padding or 8) l.SortOrder = Enum.SortOrder.LayoutOrder l.FillDirection = direction or Enum.FillDirection.Vertical l.HorizontalAlignment = Enum.HorizontalAlignment.Center l.Parent = parent return l end local function addGradient(parent, color1, color2, rotation) local g = Instance.new("UIGradient") g.Color = ColorSequence.new({ ColorSequenceKeypoint.new(0, color1), ColorSequenceKeypoint.new(1, color2 or color1), }) g.Rotation = rotation or 135 g.Parent = parent return g end local function addStroke(parent, color, thickness, transparency) local s = Instance.new("UIStroke") s.Color = color s.Thickness = thickness or 1 s.Transparency = transparency or 0 s.ApplyStrokeMode = Enum.ApplyStrokeMode.Border s.LineJoinMode = Enum.LineJoinMode.Round s.Parent = parent return s end local function wrapElement(el) return setmetatable(el, { __index = function(tbl, key) local value = rawget(tbl, key) if type(value) == "function" then return function(_, ...) return value(tbl, ...) end end return value end, }) end local function sanitizeFlag(s) return (tostring(s):gsub("[^%w_]", "_"):gsub("_+", "_")) end local function isPointInside(guiObj, x, y) if not guiObj or not guiObj.Visible then return false end local pos = guiObj.AbsolutePosition local size = guiObj.AbsoluteSize return x >= pos.X and x <= pos.X + size.X and y >= pos.Y and y <= pos.Y + size.Y end local function measureText(text, width, textSize, font) if text == "" then return 0 end return math.ceil(TextService:GetTextSize(text, textSize, font, Vector2.new(width, 10000)).Y + 2) end local function t(key) local lang = LANGUAGES[Library._currentLanguage] or LANGUAGES.en return lang[key] or LANGUAGES.en[key] or key end local function addThemedCard(parent, theme, height) local card = Instance.new("Frame") card.Size = UDim2.new(1, 0, 0, height) card.BackgroundColor3 = theme.elementColor card.BorderSizePixel = 0 card.ClipsDescendants = true card.Parent = parent addCorner(card, theme.cornerRadius) return card end local function normalizeOpts(opts) if type(opts) ~= "table" then return {} end return opts end local function colorToTable(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 getPlayer() return Players.LocalPlayer or Players.PlayerAdded:Wait() end -- Родитель GUI: gethui/CoreGui для executor, иначе PlayerGui local function getGuiParent(customParent) if customParent then return customParent end if typeof(gethui) == "function" then return gethui() end local coreGui = game:GetService("CoreGui") if coreGui then return coreGui end local player = getPlayer() return player:WaitForChild("PlayerGui", 15) end local function parentScreenGui(screenGui, parent) if syn and typeof(syn.protect_gui) == "function" then syn.protect_gui(screenGui) end if typeof(cloneref) == "function" and parent == game:GetService("CoreGui") then parent = cloneref(parent) end screenGui.Parent = parent screenGui.Enabled = true end local function httpGet(url) local ok, body = pcall(function() if game.HttpGet then return game:HttpGet(url) end if game.HttpGetAsync then return game:HttpGetAsync(url) end end) if ok and body and body ~= "" then return body end if syn and typeof(syn.request) == "function" then local res = syn.request({ Url = url, Method = "GET" }) if res and res.Body then return res.Body end end if http and typeof(http.request) == "function" then local res = http.request({ Url = url, Method = "GET" }) if res and res.Body then return res.Body end end if typeof(request) == "function" then local res = request({ Url = url, Method = "GET" }) if res and res.Body then return res.Body end end error("ALib: HttpGet недоступен в этой среде", 0) end local function loadLibraryFromUrl(url) url = url or "https://raw.githubusercontent.com/GRYurv/Lib-GUI-Roblox/main/Library.lua" local source = httpGet(url) if not source or source == "" then error("ALib: пустой ответ от сервера", 0) end if source:find("= 1 then fpsValue = fpsCounter fpsCounter = 0 lastFps = tick() end local parts = { wm._text } if wm._showFps then table.insert(parts, t("fps") .. ": " .. fpsValue) end if wm._showTime then table.insert(parts, os.date("%H:%M:%S")) end drawText.Text = table.concat(parts, " | ") drawText.Color = wm._color local vp = workspace.CurrentCamera and workspace.CurrentCamera.ViewportSize or Vector2.new(1920, 1080) local tw = #drawText.Text * 7 if position == "top-left" then drawText.Position = Vector2.new(10, 10) elseif position == "bottom-left" then drawText.Position = Vector2.new(10, vp.Y - 24) elseif position == "bottom-right" then drawText.Position = Vector2.new(vp.X - tw - 10, vp.Y - 24) else drawText.Position = Vector2.new(vp.X - tw - 10, 10) end end) else local sg = Instance.new("ScreenGui") sg.Name = "ALibWatermark" sg.ResetOnSpawn = false sg.DisplayOrder = 50 local lbl = Instance.new("TextLabel") lbl.Size = UDim2.fromOffset(400, 24) lbl.BackgroundTransparency = 1 lbl.TextColor3 = color lbl.TextSize = 14 lbl.Font = Enum.Font.Code lbl.TextXAlignment = Enum.TextXAlignment.Right lbl.Parent = sg if position == "top-left" then lbl.Position = UDim2.fromOffset(10, 10) lbl.TextXAlignment = Enum.TextXAlignment.Left elseif position == "bottom-left" then lbl.Position = UDim2.new(0, 10, 1, -30) lbl.TextXAlignment = Enum.TextXAlignment.Left elseif position == "bottom-right" then lbl.Position = UDim2.new(1, -410, 1, -30) else lbl.Position = UDim2.new(1, -410, 0, 10) end wm._gui = sg wm._label = lbl parentScreenGui(sg, getGuiParent()) wm._connection = RunService.RenderStepped:Connect(function() fpsCounter += 1 if tick() - lastFps >= 1 then fpsValue = fpsCounter fpsCounter = 0 lastFps = tick() end local parts = { wm._text } if wm._showFps then table.insert(parts, t("fps") .. ": " .. fpsValue) end if wm._showTime then table.insert(parts, os.date("%H:%M:%S")) end lbl.Text = table.concat(parts, " | ") end) end self._watermark = wm return wm end function Library:RemoveWatermark() local wm = self._watermark if not wm then return end if wm._connection then wm._connection:Disconnect() end for _, obj in ipairs(wm._objects or {}) do pcall(function() obj:Remove() end) end if wm._gui then wm._gui:Destroy() end self._watermark = nil end local function formatKeyName(keyCode) if not keyCode then return t("none") end return keyCode.Name:gsub("^Left", "L"):gsub("^Right", "R") end local function colorToHex(color) return string.format("#%02X%02X%02X", math.floor(color.R * 255 + 0.5), math.floor(color.G * 255 + 0.5), math.floor(color.B * 255 + 0.5)) end local function colorToRgbText(color) return string.format("RGB(%d, %d, %d)", math.floor(color.R * 255 + 0.5), math.floor(color.G * 255 + 0.5), math.floor(color.B * 255 + 0.5)) end local HUE_GRADIENT = ColorSequence.new({ ColorSequenceKeypoint.new(0.00, Color3.fromHSV(0, 1, 1)), ColorSequenceKeypoint.new(0.17, Color3.fromHSV(0.17, 1, 1)), ColorSequenceKeypoint.new(0.33, Color3.fromHSV(0.33, 1, 1)), ColorSequenceKeypoint.new(0.50, Color3.fromHSV(0.50, 1, 1)), ColorSequenceKeypoint.new(0.67, Color3.fromHSV(0.67, 1, 1)), ColorSequenceKeypoint.new(0.83, Color3.fromHSV(0.83, 1, 1)), ColorSequenceKeypoint.new(1.00, Color3.fromHSV(1, 1, 1)), }) local function normalizeDropdownValue(value, list) if #list == 0 then return "" end if value ~= nil then for _, item in ipairs(list) do if item == value then return value end end end return list[1] end -- ─── Context Menu ──────────────────────────────────────────────────────────── local activeContextMenu local function closeContextMenu() if activeContextMenu and activeContextMenu.Parent then activeContextMenu:Destroy() end activeContextMenu = nil end local function openContextMenu(items, position) closeContextMenu() if not items or #items == 0 then return end initTooltip() local theme = Library.Themes[Library._currentTheme] or BUILTIN_THEMES.Dark local menu = Instance.new("Frame") menu.Size = UDim2.fromOffset(140, #items * 30 + 8) menu.Position = UDim2.fromOffset(position.X, position.Y) menu.BackgroundColor3 = theme.elementColor menu.BorderSizePixel = 0 menu.ZIndex = 300 menu.Parent = tooltipGui addCorner(menu, 8) addStroke(menu, theme.strokeColor, 1, 0.3) addList(menu, 2) addPadding(menu, 4, 4, 4, 4) activeContextMenu = menu for i, item in ipairs(items) do local btn = Instance.new("TextButton") btn.Size = UDim2.new(1, 0, 0, 28) btn.BackgroundColor3 = theme.elementColor btn.Text = " " .. (item.name or "Item") btn.TextColor3 = theme.textColor btn.TextSize = 13 btn.Font = Enum.Font.GothamMedium btn.TextXAlignment = Enum.TextXAlignment.Left btn.BorderSizePixel = 0 btn.AutoButtonColor = false btn.LayoutOrder = i btn.Parent = menu addCorner(btn, 4) btn.MouseEnter:Connect(function() btn.BackgroundColor3 = theme.hoverColor end) btn.MouseLeave:Connect(function() btn.BackgroundColor3 = theme.elementColor end) btn.MouseButton1Click:Connect(function() closeContextMenu() if item.callback then item.callback() end end) end task.defer(function() local conn conn = UserInputService.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then closeContextMenu() conn:Disconnect() end end) end) end -- ─── CreateWindow ──────────────────────────────────────────────────────────── function Library:CreateWindow(config) config = config or {} if self._destroyed then error("ALib: Library destroyed", 2) end local windowName = sanitizeFlag(config.name or config.title or "ALibMenu") local win = { _name = windowName, _title = config.title or "ALib", _destroyed = false, _built = false, _visible = true, _tabs = {}, _tabOrder = {}, _tabMeta = {}, _tabContents = {}, _activeTab = nil, _sections = {}, _elements = {}, _connections = {}, _themes = deepCopy(self.Themes), _currentTheme = config.theme or self._currentTheme, _openDropdown = nil, _openColorPicker = nil, _activeKeybind = nil, _searchQuery = "", _pendingWindowState = nil, _settingsBuilt = false, _pathPrefix = windowName, } local mainW = (config.size and config.size.X) or DEFAULT_WINDOW_SIZE.X local mainH = (config.size and config.size.Y) or DEFAULT_WINDOW_SIZE.Y local minW = (config.minSize and config.minSize.X) or MIN_WINDOW_SIZE.X local minH = (config.minSize and config.minSize.Y) or MIN_WINDOW_SIZE.Y win._mainWidth = mainW win._mainHeight = mainH win._minWidth = minW win._minHeight = minH if not win._themes[win._currentTheme] then win._currentTheme = "Dark" end local theme = win._themes[win._currentTheme] or BUILTIN_THEMES.Dark local screenGui = Instance.new("ScreenGui") screenGui.Name = config.name or "ALibMenu" screenGui.ResetOnSpawn = false screenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling screenGui.DisplayOrder = config.displayOrder or 10 screenGui.IgnoreGuiInset = true parentScreenGui(screenGui, getGuiParent(config.parent)) local mainFrame = Instance.new("Frame") mainFrame.Name = "MainFrame" mainFrame.Size = UDim2.fromOffset(mainW, mainH) mainFrame.Position = config.position or UDim2.new(0.5, -mainW / 2, 0.5, -mainH / 2) mainFrame.BackgroundColor3 = theme.backgroundColor mainFrame.BorderSizePixel = 0 mainFrame.ClipsDescendants = true mainFrame.Parent = screenGui addCorner(mainFrame, MAIN_CORNER) local mainGradient = addGradient(mainFrame, theme.backgroundColor, theme.backgroundColor2, 145) local mainScale = Instance.new("UIScale") mainScale.Scale = 1 mainScale.Parent = mainFrame local sizeConstraint = Instance.new("UISizeConstraint") sizeConstraint.MinSize = Vector2.new(minW, minH) sizeConstraint.Parent = mainFrame addStroke(mainFrame, theme.strokeColor, 1, 0.35) -- Title bar local titleBar = Instance.new("Frame") titleBar.Name = "TitleBar" titleBar.Size = UDim2.new(1, 0, 0, TITLE_HEIGHT) titleBar.BackgroundColor3 = theme.tabBarColor titleBar.BorderSizePixel = 0 titleBar.ClipsDescendants = true titleBar.Parent = mainFrame addCorner(titleBar, MAIN_CORNER) addGradient(titleBar, theme.tabBarColor, theme.backgroundColor2, 90) local titleLabel = Instance.new("TextLabel") titleLabel.Size = UDim2.new(0.4, 0, 0, 22) titleLabel.Position = UDim2.fromOffset(14, 8) titleLabel.BackgroundTransparency = 1 titleLabel.Text = win._title titleLabel.TextColor3 = theme.textColor titleLabel.TextSize = 16 titleLabel.Font = Enum.Font.GothamBold titleLabel.TextXAlignment = Enum.TextXAlignment.Left titleLabel.Parent = titleBar local searchBox = Instance.new("TextBox") searchBox.Name = "Search" searchBox.Size = UDim2.new(0.35, -8, 0, SEARCH_HEIGHT - 4) searchBox.Position = UDim2.new(0.42, 0, 0, 8) searchBox.BackgroundColor3 = theme.searchBarColor searchBox.Text = "" searchBox.PlaceholderText = t("search_placeholder") searchBox.PlaceholderColor3 = theme.subTextColor searchBox.TextColor3 = theme.textColor searchBox.TextSize = 13 searchBox.Font = Enum.Font.GothamMedium searchBox.ClearTextOnFocus = false searchBox.BorderSizePixel = 0 searchBox.Parent = titleBar addCorner(searchBox, 8) addPadding(searchBox, 0, 0, 10, 10) local controls = Instance.new("Frame") controls.Size = UDim2.fromOffset(72, 32) controls.Position = UDim2.new(1, -80, 0, 10) controls.BackgroundTransparency = 1 controls.Parent = titleBar local controlsList = Instance.new("UIListLayout") controlsList.FillDirection = Enum.FillDirection.Horizontal controlsList.Padding = UDim.new(0, 8) controlsList.HorizontalAlignment = Enum.HorizontalAlignment.Right controlsList.Parent = controls local function makeWinBtn(symbol, order) local btn = Instance.new("TextButton") btn.Size = UDim2.fromOffset(28, 28) btn.BackgroundColor3 = theme.elementColor btn.BackgroundTransparency = 0.2 btn.Text = symbol btn.TextColor3 = theme.subTextColor btn.TextSize = 16 btn.Font = Enum.Font.GothamBold btn.BorderSizePixel = 0 btn.AutoButtonColor = false btn.LayoutOrder = order btn.Parent = controls addCorner(btn, 14) addStroke(btn, theme.strokeColor, 1, 0.5) return btn end local minimizeBtn = makeWinBtn("−", 1) local closeBtn = makeWinBtn("×", 2) -- Tab bar with scroll arrows local tabBar = Instance.new("Frame") tabBar.Name = "TabBar" tabBar.Size = UDim2.new(1, 0, 0, TAB_BAR_HEIGHT) tabBar.Position = UDim2.new(0, 0, 0, TITLE_HEIGHT) tabBar.BackgroundColor3 = theme.tabBarColor tabBar.BorderSizePixel = 0 tabBar.ClipsDescendants = true tabBar.Parent = mainFrame local tabLeftBtn = Instance.new("TextButton") tabLeftBtn.Size = UDim2.fromOffset(24, TAB_BAR_HEIGHT) tabLeftBtn.BackgroundColor3 = theme.tabBarColor tabLeftBtn.Text = "◀" tabLeftBtn.TextColor3 = theme.subTextColor tabLeftBtn.TextSize = 12 tabLeftBtn.Font = Enum.Font.GothamBold tabLeftBtn.BorderSizePixel = 0 tabLeftBtn.AutoButtonColor = false tabLeftBtn.Visible = false tabLeftBtn.ZIndex = 5 tabLeftBtn.Parent = tabBar local tabRightBtn = Instance.new("TextButton") tabRightBtn.Size = UDim2.fromOffset(24, TAB_BAR_HEIGHT) tabRightBtn.Position = UDim2.new(1, -24, 0, 0) tabRightBtn.BackgroundColor3 = theme.tabBarColor tabRightBtn.Text = "▶" tabRightBtn.TextColor3 = theme.subTextColor tabRightBtn.TextSize = 12 tabRightBtn.Font = Enum.Font.GothamBold tabRightBtn.BorderSizePixel = 0 tabRightBtn.AutoButtonColor = false tabRightBtn.Visible = false tabRightBtn.ZIndex = 5 tabRightBtn.Parent = tabBar local tabScroll = Instance.new("ScrollingFrame") tabScroll.Name = "TabScroll" tabScroll.Size = UDim2.new(1, -48, 1, 0) tabScroll.Position = UDim2.fromOffset(24, 0) tabScroll.BackgroundTransparency = 1 tabScroll.BorderSizePixel = 0 tabScroll.ScrollBarThickness = 0 tabScroll.ScrollingDirection = Enum.ScrollingDirection.X tabScroll.AutomaticCanvasSize = Enum.AutomaticSize.X tabScroll.CanvasSize = UDim2.new() tabScroll.Parent = tabBar local tabList = Instance.new("UIListLayout") tabList.FillDirection = Enum.FillDirection.Horizontal tabList.Padding = UDim.new(0, 4) tabList.SortOrder = Enum.SortOrder.LayoutOrder tabList.VerticalAlignment = Enum.VerticalAlignment.Center tabList.Parent = tabScroll addPadding(tabScroll, 6, 6, 4, 4) local tabIndicator = Instance.new("Frame") tabIndicator.Size = UDim2.new(0, 60, 0, 3) tabIndicator.Position = UDim2.new(0, 8, 1, -4) tabIndicator.BackgroundColor3 = theme.accentColor tabIndicator.BorderSizePixel = 0 tabIndicator.ZIndex = 2 tabIndicator.Parent = tabBar addCorner(tabIndicator, 2) local contentArea = Instance.new("Frame") contentArea.Name = "Content" contentArea.Size = UDim2.new(1, 0, 1, -(TITLE_HEIGHT + TAB_BAR_HEIGHT)) contentArea.Position = UDim2.new(0, 0, 0, TITLE_HEIGHT + TAB_BAR_HEIGHT) contentArea.BackgroundColor3 = theme.contentColor contentArea.BorderSizePixel = 0 contentArea.ClipsDescendants = true contentArea.Parent = mainFrame addCorner(contentArea, MAIN_CORNER) local dropdownOverlay = Instance.new("Frame") dropdownOverlay.Name = "Overlay" dropdownOverlay.Size = UDim2.new(1, 0, 1, 0) dropdownOverlay.BackgroundTransparency = 1 dropdownOverlay.ZIndex = 100 dropdownOverlay.ClipsDescendants = false dropdownOverlay.Parent = mainFrame -- Resize handles local resizeHandles = {} local resizeDirs = { { name = "BR", anchor = Vector2.new(1, 1), pos = UDim2.new(1, -8, 1, -8), size = UDim2.fromOffset(16, 16), cursor = "SE" }, { name = "R", anchor = Vector2.new(1, 0.5), pos = UDim2.new(1, -4, 0.5, 0), size = UDim2.fromOffset(8, 40), cursor = "E" }, { name = "B", anchor = Vector2.new(0.5, 1), pos = UDim2.new(0.5, 0, 1, -4), size = UDim2.fromOffset(40, 8), cursor = "S" }, } for _, info in ipairs(resizeDirs) do local h = Instance.new("TextButton") h.Name = "Resize_" .. info.name h.Size = info.size h.Position = info.pos h.AnchorPoint = info.anchor h.BackgroundTransparency = 1 h.Text = "" h.ZIndex = 30 h.Parent = mainFrame resizeHandles[info.name] = { btn = h, dir = info.cursor } end win._gui = { screenGui = screenGui, mainFrame = mainFrame, mainScale = mainScale, mainGradient = mainGradient, titleBar = titleBar, titleLabel = titleLabel, searchBox = searchBox, minimizeBtn = minimizeBtn, closeBtn = closeBtn, tabBar = tabBar, tabScroll = tabScroll, tabLeftBtn = tabLeftBtn, tabRightBtn = tabRightBtn, tabIndicator = tabIndicator, contentArea = contentArea, dropdownOverlay = dropdownOverlay, } local function conn(signal, fn) local c = signal:Connect(fn) table.insert(win._connections, c) return c end function win:_getTheme() return self._themes[self._currentTheme] or BUILTIN_THEMES.Dark end function win:_conn(signal, fn) return conn(signal, fn) end function win:_registerElement(el) table.insert(self._elements, el) table.insert(Library._elements, el) return wrapElement(el) end function win:_closePopups(except) if self._openDropdown and self._openDropdown ~= except then self._openDropdown:Close() end if self._openColorPicker and self._openColorPicker ~= except then self._openColorPicker:Close() end if self._activeKeybind and self._activeKeybind ~= except then self._activeKeybind:CancelListen() end end function win:_makeFlag(tabName, sectionName, elementName, customFlag) if customFlag and customFlag ~= "" then return sanitizeFlag(customFlag) end return sanitizeFlag(self._pathPrefix .. "_" .. tabName .. "_" .. sectionName .. "_" .. elementName) end function win:_registerFlag(flag, element, typeName) Library:RegisterFlag(flag, element, function() local v = element:GetValue() if typeof(v) == "Color3" then return colorToTable(v) end if typeof(v) == "EnumItem" then return v.Name end return v end, function(value) if element.SetValue then if typeName == "color" and type(value) == "table" then element:SetValue(tableToColor(value)) elseif typeName == "bind" then if type(value) == "string" and value ~= "" and Enum.KeyCode[value] then element:SetValue(Enum.KeyCode[value]) else element:SetValue(nil) end else element:SetValue(value) end end end) end function win:_updateTabArrows() local scroll = self._gui.tabScroll local needsScroll = scroll.CanvasSize.X.Offset > scroll.AbsoluteSize.X + 2 self._gui.tabLeftBtn.Visible = needsScroll self._gui.tabRightBtn.Visible = needsScroll if needsScroll then scroll.Size = UDim2.new(1, -48, 1, 0) scroll.Position = UDim2.fromOffset(24, 0) else scroll.Size = UDim2.new(1, -16, 1, 0) scroll.Position = UDim2.fromOffset(8, 0) end end function win:_scrollTabIntoView(tabName) local meta = self._tabMeta[tabName] if not meta or not meta.wrap then return end task.defer(function() local scroll = self._gui.tabScroll local wrap = meta.wrap local relX = wrap.AbsolutePosition.X - scroll.AbsolutePosition.X + scroll.CanvasPosition.X local wrapW = wrap.AbsoluteSize.X local viewW = scroll.AbsoluteSize.X local cp = scroll.CanvasPosition if relX < cp.X then scroll.CanvasPosition = Vector2.new(relX - 8, 0) elseif relX + wrapW > cp.X + viewW then scroll.CanvasPosition = Vector2.new(relX + wrapW - viewW + 8, 0) end end) end function win:_updateTabIndicator(tabName) local meta = self._tabMeta[tabName] if not meta or not meta.wrap then return end task.defer(function() if not meta.wrap.Parent then return end local x = meta.wrap.AbsolutePosition.X - self._gui.tabBar.AbsolutePosition.X local w = meta.wrap.AbsoluteSize.X tween(self._gui.tabIndicator, { Position = UDim2.new(0, x, 1, -4), Size = UDim2.new(0, math.max(w, 40), 0, 3), }, TWEEN_TAB):Play() end) end function win:_switchTab(tabName) if self._activeTab == tabName then return end local th = self:_getTheme() for name, content in pairs(self._tabContents) do content.frame.Visible = (name == tabName) end for name, meta in pairs(self._tabMeta) do meta.active = (name == tabName) meta.button.TextColor3 = meta.active and th.accentColor or th.subTextColor meta.button.Font = meta.active and Enum.Font.GothamBold or Enum.Font.GothamMedium end self._activeTab = tabName self:_updateTabIndicator(tabName) self:_scrollTabIntoView(tabName) end function win:_applySearch() local query = string.lower(self._searchQuery) for _, el in ipairs(self._elements) do if el._searchText and el.instance then local match = query == "" or string.find(string.lower(el._searchText), query, 1, true) if el._row then el._row.Visible = match end el._searchVisible = match end end for _, section in pairs(self._sections) do if section._frame then local anyVisible = false if section._container then for _, child in ipairs(section._container:GetChildren()) do if child:IsA("Frame") and child.Name == "ElementRow" and child.Visible then anyVisible = true break end end end section._frame.Visible = query == "" or anyVisible end end end function win:_applyWindowState(state) if not state then return end local mf = self._gui.mainFrame if state.w and state.h then mf.Size = UDim2.fromOffset(state.w, state.h) self._mainWidth = state.w self._mainHeight = state.h end if state.x and state.y then mf.Position = UDim2.fromOffset(state.x, state.y) end -- visible из конфига не применяем при старте — иначе меню может быть скрыто end function win:Show() if self._destroyed then return end self._visible = true local g = self._gui g.screenGui.Enabled = true g.mainFrame.Visible = true g.mainFrame.BackgroundTransparency = 0 g.mainScale.Scale = 1 end function win:Hide() if self._destroyed then return end self._visible = false self._gui.mainFrame.Visible = false end function win:ApplyTheme(themeName) if not self._themes[themeName] then return end self._currentTheme = themeName local th = self:_getTheme() local g = self._gui g.mainFrame.BackgroundColor3 = th.backgroundColor g.mainGradient.Color = ColorSequence.new({ ColorSequenceKeypoint.new(0, th.backgroundColor), ColorSequenceKeypoint.new(1, th.backgroundColor2), }) g.titleBar.BackgroundColor3 = th.tabBarColor g.titleLabel.TextColor3 = th.textColor g.searchBox.BackgroundColor3 = th.searchBarColor g.searchBox.TextColor3 = th.textColor g.searchBox.PlaceholderColor3 = th.subTextColor g.tabBar.BackgroundColor3 = th.tabBarColor g.contentArea.BackgroundColor3 = th.contentColor g.tabIndicator.BackgroundColor3 = th.accentColor g.minimizeBtn.BackgroundColor3 = th.elementColor g.closeBtn.BackgroundColor3 = th.elementColor for name, meta in pairs(self._tabMeta) do meta.button.TextColor3 = meta.active and th.accentColor or th.subTextColor end for _, el in ipairs(self._elements) do if el._applyTheme then el:_applyTheme(th) end end if self._activeTab then self:_updateTabIndicator(self._activeTab) end end function win:Close() if self._destroyed then return end self:_closePopups() self._visible = false self._gui.mainFrame.Visible = false end function win:Destroy() if self._destroyed then return end self._destroyed = true self:_closePopups() for _, c in ipairs(self._connections) do c:Disconnect() end self._connections = {} if self._gui.screenGui then self._gui.screenGui:Destroy() end for i, w in ipairs(Library._windows) do if w == self then table.remove(Library._windows, i) break end end if Library._activeWindow == self then Library._activeWindow = nil end end -- Drag title bar local dragging, dragStart, frameStart local dragHandle = Instance.new("Frame") dragHandle.Size = UDim2.new(1, -88, 0, TITLE_HEIGHT - SEARCH_HEIGHT) dragHandle.BackgroundTransparency = 1 dragHandle.Parent = titleBar conn(dragHandle.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true dragStart = input.Position frameStart = mainFrame.Position end end) conn(UserInputService.InputChanged, function(input) if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then local delta = input.Position - dragStart mainFrame.Position = UDim2.new( frameStart.X.Scale, frameStart.X.Offset + delta.X, frameStart.Y.Scale, frameStart.Y.Offset + delta.Y ) end end) conn(UserInputService.InputEnded, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = false end end) -- Resize local resizing, resizeDir, resizeStart, sizeStart, posStart for name, handle in pairs(resizeHandles) do conn(handle.btn.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then resizing = true resizeDir = handle.dir resizeStart = input.Position sizeStart = mainFrame.Size posStart = mainFrame.Position end end) end conn(UserInputService.InputChanged, function(input) if not resizing then return end if input.UserInputType ~= Enum.UserInputType.MouseMovement then return end local delta = input.Position - resizeStart local newW = math.max(minW, sizeStart.X.Offset + (resizeDir == "SE" or resizeDir == "E" and delta.X or 0)) local newH = math.max(minH, sizeStart.Y.Offset + (resizeDir == "SE" or resizeDir == "S" and delta.Y or 0)) mainFrame.Size = UDim2.fromOffset(newW, newH) win._mainWidth = newW win._mainHeight = newH end) conn(UserInputService.InputEnded, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then resizing = false end end) conn(closeBtn.MouseButton1Click, function() win:Close() end) conn(minimizeBtn.MouseButton1Click, function() win:Close() end) conn(tabLeftBtn.MouseButton1Click, function() local scroll = win._gui.tabScroll scroll.CanvasPosition = Vector2.new(math.max(0, scroll.CanvasPosition.X - 80), 0) end) conn(tabRightBtn.MouseButton1Click, function() local scroll = win._gui.tabScroll scroll.CanvasPosition = Vector2.new(scroll.CanvasPosition.X + 80, 0) end) conn(searchBox:GetPropertyChangedSignal("Text"), function() win._searchQuery = searchBox.Text win:_applySearch() end) conn(tabList:GetPropertyChangedSignal("AbsoluteContentSize"), function() win:_updateTabArrows() end) -- Global input for keybinds and popup close conn(UserInputService.InputBegan, function(input) if win._destroyed then return end if win._activeKeybind and input.UserInputType == Enum.UserInputType.Keyboard then local kb = win._activeKeybind if input.KeyCode == Enum.KeyCode.Escape then kb:CancelListen() elseif input.KeyCode == Enum.KeyCode.Backspace or input.KeyCode == Enum.KeyCode.Delete then kb:SetKey(nil) kb:CancelListen() else kb:SetKey(input.KeyCode) kb:CancelListen() end return end if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then local pos = input.Position if win._openColorPicker then local cp = win._openColorPicker if not isPointInside(cp._container, pos.X, pos.Y) and not isPointInside(cp._panel, pos.X, pos.Y) then cp:Close() end end if win._openDropdown then local dd = win._openDropdown if not isPointInside(dd._container, pos.X, pos.Y) and not isPointInside(dd._listFrame, pos.X, pos.Y) then dd:Close() end end closeContextMenu() end end) function win:_registerTabUI(tabName, icon) if self._tabContents[tabName] then return self._tabContents[tabName] end local layoutOrder = #self._tabOrder + 1 table.insert(self._tabOrder, tabName) local th = self:_getTheme() local tabWrap = Instance.new("Frame") tabWrap.Name = tabName .. "_Wrap" tabWrap.Size = UDim2.new(0, 0, 0, 32) tabWrap.AutomaticSize = Enum.AutomaticSize.X tabWrap.BackgroundTransparency = 1 tabWrap.LayoutOrder = layoutOrder tabWrap.Parent = self._gui.tabScroll addCorner(tabWrap, 8) local inner = Instance.new("Frame") inner.Size = UDim2.new(0, 0, 1, 0) inner.AutomaticSize = Enum.AutomaticSize.X inner.BackgroundTransparency = 1 inner.Parent = tabWrap local innerList = Instance.new("UIListLayout") innerList.FillDirection = Enum.FillDirection.Horizontal innerList.Padding = UDim.new(0, 4) innerList.VerticalAlignment = Enum.VerticalAlignment.Center innerList.Parent = inner addPadding(inner, 0, 0, 8, 8) if icon and icon ~= "" then if string.find(icon, "rbxassetid://") or string.find(icon, "http") then local iconLbl = Instance.new("ImageLabel") iconLbl.Size = UDim2.fromOffset(18, 18) iconLbl.BackgroundTransparency = 1 iconLbl.Image = icon iconLbl.LayoutOrder = 1 iconLbl.Parent = inner else local sym = Instance.new("TextLabel") sym.Size = UDim2.fromOffset(18, 18) sym.BackgroundTransparency = 1 sym.Text = icon sym.TextSize = 14 sym.Font = Enum.Font.GothamBold sym.TextColor3 = th.subTextColor sym.LayoutOrder = 1 sym.Parent = inner end end local tabBtn = Instance.new("TextButton") tabBtn.Name = tabName tabBtn.Size = UDim2.new(0, 0, 1, 0) tabBtn.AutomaticSize = Enum.AutomaticSize.X tabBtn.BackgroundTransparency = 1 tabBtn.Text = tabName tabBtn.TextColor3 = th.subTextColor tabBtn.TextSize = 14 tabBtn.Font = Enum.Font.GothamMedium tabBtn.BorderSizePixel = 0 tabBtn.AutoButtonColor = false tabBtn.LayoutOrder = 2 tabBtn.Parent = inner self._tabMeta[tabName] = { wrap = tabWrap, button = tabBtn, active = false } conn(tabBtn.MouseButton1Click, function() win:_switchTab(tabName) end) local tabFrame = Instance.new("Frame") tabFrame.Name = "Tab_" .. tabName tabFrame.Size = UDim2.new(1, 0, 1, 0) tabFrame.BackgroundTransparency = 1 tabFrame.Visible = false tabFrame.ClipsDescendants = true tabFrame.Parent = self._gui.contentArea local scroll = Instance.new("ScrollingFrame") scroll.Name = "Scroll" scroll.Size = UDim2.new(1, 0, 1, 0) scroll.BackgroundTransparency = 1 scroll.BorderSizePixel = 0 scroll.ScrollBarThickness = 4 scroll.ScrollBarImageColor3 = th.accentColor scroll.CanvasSize = UDim2.new() scroll.AutomaticCanvasSize = Enum.AutomaticSize.Y scroll.ClipsDescendants = false scroll.Parent = tabFrame addList(scroll, 10) addPadding(scroll, 12, 12, 12, 12) self._tabContents[tabName] = { frame = tabFrame, scroll = scroll, _order = 0 } if not self._activeTab then self:_switchTab(tabName) end task.defer(function() win:_updateTabArrows() end) return self._tabContents[tabName] end function win:AddTab(name, icon) assert(type(name) == "string" and name ~= "", "ALib: AddTab requires non-empty name") if self._tabs[name] then return self._tabs[name] end if name == t("settings") and not self._buildingSettings then warn("ALib: Settings tab is created automatically in Build()") end self:_registerTabUI(name, icon) local tab = { _window = self, _name = name, _sections = {} } self._tabs[name] = tab function tab:AddSection(sectionName) assert(sectionName and sectionName ~= "", "ALib: section name required") local w = self._window local content = w._tabContents[self._name] if not content then return nil end content._order = (content._order or 0) + 1 local sectionFrame = Instance.new("Frame") sectionFrame.Name = "Section_" .. sanitizeFlag(sectionName) sectionFrame.Size = UDim2.new(1, -4, 0, 0) sectionFrame.AutomaticSize = Enum.AutomaticSize.Y sectionFrame.BackgroundTransparency = 1 sectionFrame.LayoutOrder = content._order sectionFrame.Parent = content.scroll local secList = addList(sectionFrame, 6) secList.HorizontalAlignment = Enum.HorizontalAlignment.Left local header = Instance.new("TextLabel") header.Name = "Header" header.Size = UDim2.new(1, 0, 0, 24) header.BackgroundTransparency = 1 header.Text = sectionName header.TextColor3 = w:_getTheme().accentColor header.TextSize = 15 header.Font = Enum.Font.GothamBold header.TextXAlignment = Enum.TextXAlignment.Left header.LayoutOrder = 1 header.Parent = sectionFrame local container = Instance.new("Frame") container.Name = "Container" container.Size = UDim2.new(1, 0, 0, 0) container.AutomaticSize = Enum.AutomaticSize.Y container.BackgroundTransparency = 1 container.LayoutOrder = 2 container.Parent = sectionFrame addList(container, 6) addPadding(container, 0, 4, 4, 4) local section = { _window = w, _tabName = self._name, _name = sectionName, _container = container, _header = header, _frame = sectionFrame, } w._sections[self._name .. "/" .. sectionName] = section self._sections[sectionName] = section local function nextOrder() container._order = (container._order or 0) + 1 return container._order end local function makeRow(height) local row = Instance.new("Frame") row.Name = "ElementRow" row.Size = UDim2.new(1, 0, 0, height) row.BackgroundTransparency = 1 row.LayoutOrder = nextOrder() row.ClipsDescendants = false row.Parent = container return row end local function makeLabel(parent, text, size, color, bold) local lbl = Instance.new("TextLabel") lbl.BackgroundTransparency = 1 lbl.Text = text or "" lbl.TextColor3 = color or w:_getTheme().textColor lbl.TextSize = size or 14 lbl.Font = bold and Enum.Font.GothamBold or Enum.Font.GothamMedium lbl.TextXAlignment = Enum.TextXAlignment.Left lbl.TextTruncate = Enum.TextTruncate.AtEnd lbl.Parent = parent return lbl end local function setupElement(el, opts, name, description) opts = normalizeOpts(opts) el._searchText = (name or "") .. " " .. (description or opts.description or "") el._row = el.instance el._tooltip = opts.tooltip if el._hoverTarget then attachTooltip(el._hoverTarget, function() return el._tooltip end) end if opts.contextMenu then el:AddContextMenu(opts.contextMenu) end local flag = w:_makeFlag(self._name, sectionName, name, opts.flag) el._flag = flag if el.GetValue then w:_registerFlag(flag, el, el.type) end return w:_registerElement(el) end function section:AddButton(name, callback, opts) opts = normalizeOpts(opts) local th = w:_getTheme() local h = math.max(MIN_TOUCH, th.elementHeight) local row = makeRow(h) local accent = opts.color or th.accentColor local btn = Instance.new("TextButton") btn.Size = UDim2.new(1, 0, 1, 0) btn.BackgroundColor3 = accent btn.Text = name btn.TextColor3 = th.buttonTextColor btn.TextSize = 14 btn.Font = Enum.Font.GothamBold btn.BorderSizePixel = 0 btn.AutoButtonColor = false btn.Parent = row addCorner(btn, th.cornerRadius) conn(btn.MouseButton1Click, function() if callback then callback() end end) local el = { type = "button", instance = row, _hoverTarget = btn, SetText = function(_, t) btn.Text = t end, SetVisible = function(_, v) row.Visible = v end, SetTooltip = function(_, tip) el._tooltip = tip end, AddContextMenu = function(_, items) conn(btn.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton2 then openContextMenu(items, input.Position) end end) end, _applyTheme = function(_, t) btn.BackgroundColor3 = opts.color or t.accentColor btn.TextColor3 = t.buttonTextColor end, } return setupElement(el, opts, name, opts.description) end function section:AddToggle(name, default, callback, opts) opts = normalizeOpts(opts) local th = w:_getTheme() local h = math.max(MIN_TOUCH, th.elementHeight) local state = default or false local row = makeRow(h) local card = addThemedCard(row, th, h) local lbl = makeLabel(card, name, 14, th.textColor, false) lbl.Size = UDim2.new(1, -56, 1, 0) lbl.Position = UDim2.fromOffset(12, 0) local track = Instance.new("Frame") track.Size = UDim2.fromOffset(44, 24) track.Position = UDim2.new(1, -52, 0.5, -12) track.BackgroundColor3 = state and th.toggleOnColor or th.toggleOffColor track.BorderSizePixel = 0 track.Parent = card addCorner(track, 12) local knob = Instance.new("Frame") knob.Size = UDim2.fromOffset(20, 20) knob.Position = state and UDim2.new(1, -22, 0.5, -10) or UDim2.new(0, 2, 0.5, -10) knob.BackgroundColor3 = th.knobColor knob.BorderSizePixel = 0 knob.Parent = track addCorner(knob, 10) local hit = Instance.new("TextButton") hit.Size = UDim2.new(1, 0, 1, 0) hit.BackgroundTransparency = 1 hit.Text = "" hit.Parent = card local function setState(val, fire) local t = w:_getTheme() state = val tween(track, { BackgroundColor3 = state and t.toggleOnColor or t.toggleOffColor }):Play() tween(knob, { Position = state and UDim2.new(1, -22, 0.5, -10) or UDim2.new(0, 2, 0.5, -10) }):Play() if fire ~= false and callback then callback(state) end Library:SaveConfig() end conn(hit.MouseButton1Click, function() setState(not state) end) local el = { type = "toggle", instance = row, _hoverTarget = card, GetValue = function() return state end, SetValue = function(_, v) setState(v) end, SetVisible = function(_, v) row.Visible = v end, SetTooltip = function(_, tip) el._tooltip = tip end, AddContextMenu = function(_, items) conn(card.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton2 then openContextMenu(items, input.Position) end end) end, _applyTheme = function(_, t) card.BackgroundColor3 = t.elementColor lbl.TextColor3 = t.textColor track.BackgroundColor3 = state and t.toggleOnColor or t.toggleOffColor knob.BackgroundColor3 = t.knobColor end, } return setupElement(el, opts, name, opts.description) end function section:AddSlider(name, minVal, maxVal, default, callback, opts) opts = normalizeOpts(opts) local th = w:_getTheme() minVal = minVal or 0 maxVal = maxVal or 100 local value = math.clamp(default or minVal, minVal, maxVal) local h = math.max(MIN_TOUCH, th.elementHeight + 8) local row = makeRow(h) local card = addThemedCard(row, th, h) local lbl = makeLabel(card, name, 13, th.textColor, false) lbl.Size = UDim2.new(0.6, 0, 0, 20) lbl.Position = UDim2.fromOffset(12, 6) local valLbl = makeLabel(card, tostring(value), 13, th.accentColor, true) valLbl.Size = UDim2.new(0.3, 0, 0, 20) valLbl.Position = UDim2.new(0.7, -12, 0, 6) valLbl.TextXAlignment = Enum.TextXAlignment.Right local track = Instance.new("Frame") track.Size = UDim2.new(1, -24, 0, 6) track.Position = UDim2.new(0, 12, 1, -16) track.BackgroundColor3 = th.strokeColor track.BorderSizePixel = 0 track.Parent = card addCorner(track, 3) local fill = Instance.new("Frame") fill.Size = UDim2.new((value - minVal) / math.max(maxVal - minVal, 1), 0, 1, 0) fill.BackgroundColor3 = th.accentColor fill.BorderSizePixel = 0 fill.Parent = track addCorner(fill, 3) local knob = Instance.new("Frame") knob.Size = UDim2.fromOffset(16, 16) knob.AnchorPoint = Vector2.new(0.5, 0.5) knob.Position = UDim2.new((value - minVal) / math.max(maxVal - minVal, 1), 0, 0.5, 0) knob.BackgroundColor3 = th.knobColor knob.BorderSizePixel = 0 knob.ZIndex = 2 knob.Parent = track addCorner(knob, 8) local dragging = false local function setValue(v, fire) value = math.clamp(math.floor(v + 0.5), minVal, maxVal) local pct = (value - minVal) / math.max(maxVal - minVal, 1) fill.Size = UDim2.new(pct, 0, 1, 0) knob.Position = UDim2.new(pct, 0, 0.5, 0) valLbl.Text = tostring(value) if fire ~= false and callback then callback(value) end Library:SaveConfig() end local function updateFromInput(input) local tp = track.AbsolutePosition.X local ts = track.AbsoluteSize.X setValue(minVal + math.clamp((input.Position.X - tp) / ts, 0, 1) * (maxVal - minVal)) end conn(track.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true updateFromInput(input) end end) conn(knob.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then dragging = true end end) conn(UserInputService.InputChanged, function(input) if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then updateFromInput(input) end end) conn(UserInputService.InputEnded, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = false end end) local el = { type = "slider", instance = row, _hoverTarget = card, GetValue = function() return value end, SetValue = function(_, v) setValue(v) end, SetVisible = function(_, v) row.Visible = v end, SetTooltip = function(_, tip) el._tooltip = tip end, AddContextMenu = function(_, items) conn(card.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton2 then openContextMenu(items, input.Position) end end) end, _applyTheme = function(_, t) card.BackgroundColor3 = t.elementColor lbl.TextColor3 = t.textColor valLbl.TextColor3 = t.accentColor track.BackgroundColor3 = t.strokeColor fill.BackgroundColor3 = t.accentColor knob.BackgroundColor3 = t.knobColor end, } return setupElement(el, opts, name, opts.description) end function section:AddLabel(text) local th = w:_getTheme() local row = makeRow(24) local lbl = makeLabel(row, text, 13, th.subTextColor, false) lbl.Size = UDim2.new(1, 0, 1, 0) local el = { type = "label", instance = row, SetText = function(_, t) lbl.Text = t end, SetVisible = function(_, v) row.Visible = v end, _applyTheme = function(_, t) lbl.TextColor3 = t.subTextColor end, } el._searchText = text or "" el._row = row return w:_registerElement(el) end function section:AddParagraph(title, text) local th = w:_getTheme() local titleH = measureText(title or "", 400, 15, Enum.Font.GothamBold) local textH = measureText(text or "", 400, 12, Enum.Font.GothamMedium) local row = makeRow(titleH + textH + 12) local tLbl = makeLabel(row, title, 15, th.textColor, true) tLbl.Size = UDim2.new(1, 0, 0, titleH) tLbl.TextWrapped = true local bLbl = makeLabel(row, text, 12, th.subTextColor, false) bLbl.Size = UDim2.new(1, 0, 0, textH) bLbl.Position = UDim2.new(0, 0, 0, titleH + 4) bLbl.TextWrapped = true local el = { type = "paragraph", instance = row, SetText = function(_, newTitle, newText) if newTitle then tLbl.Text = newTitle end if newText then bLbl.Text = newText end end, SetVisible = function(_, v) row.Visible = v end, _applyTheme = function(_, t) tLbl.TextColor3 = t.textColor bLbl.TextColor3 = t.subTextColor end, } el._searchText = (title or "") .. " " .. (text or "") el._row = row return w:_registerElement(el) end function section:AddDropdown(name, options, default, callback, opts) opts = normalizeOpts(opts) local th = w:_getTheme() local list = options or {} local selected = normalizeDropdownValue(default, list) local h = math.max(MIN_TOUCH, th.elementHeight) local row = makeRow(h) row.ClipsDescendants = false local container = Instance.new("Frame") container.Size = UDim2.new(1, 0, 1, 0) container.BackgroundColor3 = th.elementColor container.BorderSizePixel = 0 container.ClipsDescendants = true container.Parent = row addCorner(container, th.cornerRadius) local lbl = makeLabel(container, name, 13, th.textColor, false) lbl.Size = UDim2.new(0.4, 0, 1, 0) lbl.Position = UDim2.fromOffset(12, 0) local displayBtn = Instance.new("TextButton") displayBtn.Size = UDim2.new(0.55, -8, 0, math.max(28, h - 8)) displayBtn.Position = UDim2.new(0.43, 0, 0.5, 0) displayBtn.AnchorPoint = Vector2.new(0, 0.5) displayBtn.BackgroundColor3 = th.contentColor displayBtn.Text = tostring(selected) displayBtn.TextColor3 = th.textColor displayBtn.TextSize = 13 displayBtn.Font = Enum.Font.GothamMedium displayBtn.BorderSizePixel = 0 displayBtn.AutoButtonColor = false displayBtn.Parent = container addCorner(displayBtn, 6) local arrow = makeLabel(displayBtn, "▼", 10, th.subTextColor, false) arrow.Size = UDim2.new(0, 16, 1, 0) arrow.Position = UDim2.new(1, -18, 0, 0) arrow.TextXAlignment = Enum.TextXAlignment.Center local listFrame = Instance.new("Frame") listFrame.Size = UDim2.fromOffset(0, 0) listFrame.BackgroundColor3 = th.contentColor listFrame.BorderSizePixel = 0 listFrame.ClipsDescendants = true listFrame.Visible = false listFrame.ZIndex = 50 listFrame.Parent = w._gui.dropdownOverlay addCorner(listFrame, 8) addList(listFrame, 2) addPadding(listFrame, 4, 4, 4, 4) local itemButtons = {} local isOpen = false local maxH = math.min(#list * 34 + 8, 180) local listW = 0 local dd = { _container = container, _listFrame = listFrame } local function positionList() local bp = displayBtn.AbsolutePosition local bs = displayBtn.AbsoluteSize local op = w._gui.dropdownOverlay.AbsolutePosition listW = bs.X listFrame.Position = UDim2.fromOffset(bp.X - op.X, bp.Y - op.Y + bs.Y + 4) end local function refreshChecks() for item, btn in pairs(itemButtons) do local check = btn:FindFirstChild("Check") if check then check.Text = item == selected and "✓" or "" check.TextColor3 = w:_getTheme().accentColor end end end function dd:Close() if not isOpen then return end isOpen = false if w._openDropdown == self then w._openDropdown = nil end tween(listFrame, { Size = UDim2.fromOffset(listW, 0) }, TWEEN_OPEN):Play() task.delay(0.2, function() if listFrame.Parent then listFrame.Visible = false end end) arrow.Text = "▼" end function dd:Open() w:_closePopups(self) isOpen = true w._openDropdown = self positionList() listFrame.Visible = true listFrame.Size = UDim2.fromOffset(listW, 0) tween(listFrame, { Size = UDim2.fromOffset(listW, maxH) }, TWEEN_OPEN):Play() arrow.Text = "▲" refreshChecks() end for _, item in ipairs(list) do local itemBtn = Instance.new("TextButton") itemBtn.Size = UDim2.new(1, -4, 0, 30) itemBtn.BackgroundColor3 = th.elementColor itemBtn.Text = " " .. tostring(item) itemBtn.TextColor3 = th.textColor itemBtn.TextSize = 13 itemBtn.Font = Enum.Font.GothamMedium itemBtn.TextXAlignment = Enum.TextXAlignment.Left itemBtn.BorderSizePixel = 0 itemBtn.AutoButtonColor = false itemBtn.ZIndex = 51 itemBtn.Parent = listFrame addCorner(itemBtn, 4) local check = Instance.new("TextLabel") check.Name = "Check" check.Size = UDim2.fromOffset(20, 30) check.Position = UDim2.new(1, -22, 0, 0) check.BackgroundTransparency = 1 check.Text = "" check.TextSize = 14 check.Font = Enum.Font.GothamBold check.ZIndex = 52 check.Parent = itemBtn itemButtons[item] = itemBtn conn(itemBtn.MouseButton1Click, function() selected = item displayBtn.Text = tostring(selected) refreshChecks() dd:Close() if callback then callback(selected) end Library:SaveConfig() end) end conn(displayBtn.MouseButton1Click, function() if isOpen then dd:Close() else dd:Open() end end) local el = { type = "dropdown", instance = row, _hoverTarget = container, GetValue = function() return selected end, SetValue = function(_, v) selected = normalizeDropdownValue(v, list) displayBtn.Text = tostring(selected) refreshChecks() if callback then callback(selected) end end, SetVisible = function(_, v) row.Visible = v end, Close = function() dd:Close() end, _applyTheme = function(_, t) container.BackgroundColor3 = t.elementColor lbl.TextColor3 = t.textColor displayBtn.BackgroundColor3 = t.contentColor displayBtn.TextColor3 = t.textColor listFrame.BackgroundColor3 = t.contentColor end, } return setupElement(el, opts, name, opts.description) end function section:AddColorpicker(name, default, callback, opts) opts = normalizeOpts(opts) local th = w:_getTheme() local h = math.max(MIN_TOUCH, th.elementHeight) local color = default or Color3.fromRGB(255, 255, 255) local hue, sat, val = color:ToHSV() local row = makeRow(h) row.ClipsDescendants = false local container = Instance.new("Frame") container.Size = UDim2.new(1, 0, 1, 0) container.BackgroundColor3 = th.elementColor container.BorderSizePixel = 0 container.Parent = row addCorner(container, th.cornerRadius) local lbl = makeLabel(container, name, 13, th.textColor, false) lbl.Size = UDim2.new(0.42, 0, 1, 0) lbl.Position = UDim2.fromOffset(12, 0) local previewBtn = Instance.new("TextButton") previewBtn.Size = UDim2.new(0.52, -8, 0, math.max(28, h - 8)) previewBtn.Position = UDim2.new(0.46, 0, 0.5, 0) previewBtn.AnchorPoint = Vector2.new(0, 0.5) previewBtn.BackgroundColor3 = color previewBtn.Text = colorToHex(color) previewBtn.TextColor3 = (color.R * 0.299 + color.G * 0.587 + color.B * 0.114) > 0.55 and Color3.new(0, 0, 0) or Color3.new(1, 1, 1) previewBtn.TextSize = 12 previewBtn.Font = Enum.Font.GothamBold previewBtn.BorderSizePixel = 0 previewBtn.AutoButtonColor = false previewBtn.Parent = container addCorner(previewBtn, 6) local panel = Instance.new("Frame") panel.Size = UDim2.fromOffset(220, 0) panel.BackgroundColor3 = th.contentColor panel.BorderSizePixel = 0 panel.ClipsDescendants = true panel.Visible = false panel.ZIndex = 60 panel.Parent = w._gui.dropdownOverlay addCorner(panel, 10) addList(panel, 8) addPadding(panel, 10, 10, 10, 10) local sbArea = Instance.new("Frame") sbArea.Size = UDim2.new(1, 0, 0, 100) sbArea.BackgroundTransparency = 1 sbArea.LayoutOrder = 2 sbArea.Parent = panel local sbBg = Instance.new("Frame") sbBg.Size = UDim2.new(1, 0, 1, 0) sbBg.BorderSizePixel = 0 sbBg.Parent = sbArea addCorner(sbBg, 6) local satOverlay = Instance.new("Frame") satOverlay.Size = UDim2.new(1, 0, 1, 0) satOverlay.BackgroundColor3 = Color3.new(1, 1, 1) satOverlay.BorderSizePixel = 0 satOverlay.Parent = sbBg addCorner(satOverlay, 6) local satGrad = Instance.new("UIGradient") satGrad.Transparency = NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 1), }) satGrad.Parent = satOverlay local valOverlay = Instance.new("Frame") valOverlay.Size = UDim2.new(1, 0, 1, 0) valOverlay.BackgroundColor3 = Color3.new(0, 0, 0) valOverlay.BorderSizePixel = 0 valOverlay.Parent = sbBg addCorner(valOverlay, 6) local valGrad = Instance.new("UIGradient") valGrad.Rotation = 90 valGrad.Transparency = NumberSequence.new({ NumberSequenceKeypoint.new(0, 1), NumberSequenceKeypoint.new(1, 0), }) valGrad.Parent = valOverlay local sbCursor = Instance.new("Frame") sbCursor.Size = UDim2.fromOffset(12, 12) sbCursor.AnchorPoint = Vector2.new(0.5, 0.5) sbCursor.BackgroundColor3 = Color3.new(1, 1, 1) sbCursor.BorderSizePixel = 0 sbCursor.ZIndex = 4 sbCursor.Parent = sbBg addCorner(sbCursor, 6) local hueTrack = Instance.new("Frame") hueTrack.Size = UDim2.new(1, 0, 0, 12) hueTrack.BackgroundColor3 = Color3.new(1, 1, 1) hueTrack.BorderSizePixel = 0 hueTrack.LayoutOrder = 3 hueTrack.Parent = panel addCorner(hueTrack, 6) local hueGrad = Instance.new("UIGradient") hueGrad.Color = HUE_GRADIENT hueGrad.Parent = hueTrack local hueCursor = Instance.new("Frame") hueCursor.Size = UDim2.new(0, 4, 1, 4) hueCursor.AnchorPoint = Vector2.new(0.5, 0.5) hueCursor.Position = UDim2.new(hue, 0, 0.5, 0) hueCursor.BackgroundColor3 = Color3.new(1, 1, 1) hueCursor.BorderSizePixel = 0 hueCursor.Parent = hueTrack local isOpen = false local draggingSB, draggingHue = false, false local panelHeight = 160 local cp = { _container = container, _panel = panel } local function updateFromHsv(fire) color = Color3.fromHSV(hue, sat, val) sbBg.BackgroundColor3 = Color3.fromHSV(hue, 1, 1) sbCursor.Position = UDim2.new(sat, 0, 1 - val, 0) hueCursor.Position = UDim2.new(hue, 0, 0.5, 0) previewBtn.BackgroundColor3 = color previewBtn.Text = colorToHex(color) if fire ~= false and callback then callback(color) end if fire ~= false then Library:SaveConfig() end end function cp:Close() if not isOpen then return end isOpen = false if w._openColorPicker == self then w._openColorPicker = nil end tween(panel, { Size = UDim2.fromOffset(220, 0) }, TWEEN_OPEN):Play() task.delay(0.2, function() if panel.Parent then panel.Visible = false end end) end function cp:Open() w:_closePopups(self) isOpen = true w._openColorPicker = self local bp = previewBtn.AbsolutePosition local bs = previewBtn.AbsoluteSize local op = w._gui.dropdownOverlay.AbsolutePosition panel.Position = UDim2.fromOffset(bp.X - op.X, bp.Y - op.Y + bs.Y + 4) panel.Visible = true panel.Size = UDim2.fromOffset(220, 0) updateFromHsv(false) tween(panel, { Size = UDim2.fromOffset(220, panelHeight) }, TWEEN_OPEN):Play() end local function updateSB(input) local pos = sbBg.AbsolutePosition local size = sbBg.AbsoluteSize sat = math.clamp((input.Position.X - pos.X) / size.X, 0, 1) val = 1 - math.clamp((input.Position.Y - pos.Y) / size.Y, 0, 1) updateFromHsv() end local function updateHue(input) local pos = hueTrack.AbsolutePosition local size = hueTrack.AbsoluteSize hue = math.clamp((input.Position.X - pos.X) / size.X, 0, 1) updateFromHsv() end conn(sbBg.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then draggingSB = true updateSB(input) end end) conn(hueTrack.InputBegan, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then draggingHue = true updateHue(input) end end) conn(UserInputService.InputChanged, function(input) if draggingSB and input.UserInputType == Enum.UserInputType.MouseMovement then updateSB(input) elseif draggingHue and input.UserInputType == Enum.UserInputType.MouseMovement then updateHue(input) end end) conn(UserInputService.InputEnded, function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 then draggingSB = false draggingHue = false end end) conn(previewBtn.MouseButton1Click, function() if isOpen then cp:Close() else cp:Open() end end) updateFromHsv(false) local el = { type = "color", instance = row, _hoverTarget = container, GetValue = function() return color end, SetValue = function(_, c) if typeof(c) ~= "Color3" then return end color = c hue, sat, val = c:ToHSV() updateFromHsv(false) end, SetVisible = function(_, v) row.Visible = v end, Close = function() cp:Close() end, _applyTheme = function(_, t) container.BackgroundColor3 = t.elementColor lbl.TextColor3 = t.textColor panel.BackgroundColor3 = t.contentColor end, } return setupElement(el, opts, name, opts.description) end function section:AddBind(name, defaultKey, callback, opts) opts = normalizeOpts(opts) local th = w:_getTheme() local h = math.max(MIN_TOUCH, th.elementHeight) local currentKey = defaultKey local mode = opts.mode or "toggle" local holdActive = false local row = makeRow(h) local card = addThemedCard(row, th, h) local lbl = makeLabel(card, name, 14, th.textColor, false) lbl.Size = UDim2.new(1, -130, 1, 0) lbl.Position = UDim2.fromOffset(12, 0) local modeIcon = makeLabel(card, mode == "hold" and "⬇" or "⏺", 12, th.subTextColor, false) modeIcon.Size = UDim2.fromOffset(16, 28) modeIcon.Position = UDim2.new(1, -118, 0, 0) modeIcon.TextXAlignment = Enum.TextXAlignment.Center local keyBtn = Instance.new("TextButton") keyBtn.Size = UDim2.fromOffset(84, 28) keyBtn.Position = UDim2.new(1, -96, 0.5, -14) keyBtn.BackgroundColor3 = th.contentColor keyBtn.Text = formatKeyName(currentKey) keyBtn.TextColor3 = th.textColor keyBtn.TextSize = 12 keyBtn.Font = Enum.Font.GothamBold keyBtn.BorderSizePixel = 0 keyBtn.AutoButtonColor = false keyBtn.Parent = card addCorner(keyBtn, 6) local keyStroke = addStroke(keyBtn, th.strokeColor, 1, 0.3) local listening = false local kb = {} local function updateDisplay() keyBtn.Text = listening and "..." or formatKeyName(currentKey) end local function setListen(active) listening = active if active then w:_closePopups(kb) w._activeKeybind = kb keyStroke.Color = w:_getTheme().accentColor else if w._activeKeybind == kb then w._activeKeybind = nil end keyStroke.Color = w:_getTheme().strokeColor end updateDisplay() end local function setKey(keyCode, fire) currentKey = keyCode updateDisplay() if fire ~= false and callback then callback(currentKey) end Library:SaveConfig() end function kb:SetKey(k) setKey(k) end function kb:CancelListen() setListen(false) end function kb:StartListen() setListen(true) end conn(keyBtn.MouseButton1Click, function() if listening then kb:CancelListen() else kb:StartListen() end end) -- Runtime key handling for bind modes conn(UserInputService.InputBegan, function(input) if input.UserInputType ~= Enum.UserInputType.Keyboard then return end if not currentKey or input.KeyCode ~= currentKey then return end if w._activeKeybind == kb then return end if mode == "hold" then holdActive = true if callback then callback(true) end elseif mode == "toggle" then if callback then callback(input.KeyCode) end end end) conn(UserInputService.InputEnded, function(input) if mode == "hold" and currentKey and input.KeyCode == currentKey and holdActive then holdActive = false if callback then callback(false) end end end) local el = { type = "bind", instance = row, _hoverTarget = card, GetValue = function() return currentKey end, SetValue = function(_, k) setKey(k) end, SetVisible = function(_, v) row.Visible = v end, CancelListen = function() kb:CancelListen() end, _applyTheme = function(_, t) card.BackgroundColor3 = t.elementColor lbl.TextColor3 = t.textColor keyBtn.BackgroundColor3 = t.contentColor keyBtn.TextColor3 = t.textColor modeIcon.TextColor3 = t.subTextColor end, } return setupElement(el, opts, name, opts.description) end return section end return tab end function win:Build() if self._built then return self end self._built = true self:_buildSettingsTab() if self._pendingWindowState then self:_applyWindowState(self._pendingWindowState) end self:ApplyTheme(self._currentTheme) self:Show() return self end function win:_buildSettingsTab() if self._settingsBuilt then return end self._settingsBuilt = true local settingsName = t("settings") self._buildingSettings = true local tab = self:AddTab(settingsName, "⚙") self._buildingSettings = false local sec = tab:AddSection(t("theme_editor")) local themeNames = {} for name in pairs(self._themes) do table.insert(themeNames, name) end table.sort(themeNames) sec:AddDropdown(t("theme"), themeNames, self._currentTheme, function(val) self:ApplyTheme(val) Library._currentTheme = val Library:SaveConfig() end) local colorKeys = { "backgroundColor", "accentColor", "textColor", "subTextColor", "strokeColor", "elementColor", "knobColor", "toggleOnColor", } for _, key in ipairs(colorKeys) do local th = self:_getTheme() sec:AddColorpicker(key, th[key] or Color3.new(1, 1, 1), function(c) if self._themes[self._currentTheme] then self._themes[self._currentTheme][key] = c Library.Themes[self._currentTheme][key] = c self:ApplyTheme(self._currentTheme) end end, { description = key }) end sec:AddButton(t("reset_theme"), function() local base = deepCopy(BUILTIN_THEMES.Dark) local name = self._currentTheme if BUILTIN_THEMES[name] then self._themes[name] = deepCopy(BUILTIN_THEMES[name]) Library.Themes[name] = deepCopy(BUILTIN_THEMES[name]) else for k, v in pairs(base) do self._themes[name][k] = v end end self:ApplyTheme(name) end) end table.insert(self._windows, win) self._activeWindow = win if self._pendingWindowState or win._pendingWindowState then win:_applyWindowState(win._pendingWindowState or self._pendingWindowState) end win:ApplyTheme(win._currentTheme) task.defer(function() if not win._destroyed and win.Show then win:Show() end end) return win end function Library:Toggle() local win = self._activeWindow if not win or win._destroyed then return end if not win._built then win:Build() end local mf = win._gui.mainFrame local scale = win._gui.mainScale win._visible = not win._visible if win._visible then mf.Visible = true scale.Scale = 0.85 mf.BackgroundTransparency = 1 tween(scale, { Scale = 1 }, TWEEN_WINDOW):Play() tween(mf, { BackgroundTransparency = 0 }, TWEEN_WINDOW):Play() else tween(scale, { Scale = 0.85 }, TWEEN_WINDOW):Play() tween(mf, { BackgroundTransparency = 1 }, TWEEN_WINDOW):Play() task.delay(0.22, function() if not win._visible and mf.Parent then mf.Visible = false mf.BackgroundTransparency = 0 scale.Scale = 1 end end) end self:SaveConfig() end function Library:Destroy() if self._destroyed then return end self._destroyed = true self:RemoveWatermark() closeContextMenu() hideTooltip() for _, win in ipairs(self._windows) do if not win._destroyed then win:Destroy() end end self._windows = {} self._activeWindow = nil for _, c in ipairs(self._connections) do pcall(function() c:Disconnect() end) end self._connections = {} if notifyGui then notifyGui:Destroy() notifyGui = nil end if tooltipGui then tooltipGui:Destroy() tooltipGui = nil end self._flags = {} self._elements = {} self._notifyQueue = {} self._notifyShowing = false end -- Безопасная загрузка с GitHub (с понятными ошибками в консоли) function Library.Load(url) return loadLibraryFromUrl(url) end -- Готовое демо-меню одной командой function Library:RunDemo() self:SetLanguage("ru") self:CreateTheme({ name = "Ocean", backgroundColor = Color3.fromRGB(5, 15, 30), backgroundColor2 = Color3.fromRGB(10, 25, 50), accentColor = Color3.fromRGB(0, 200, 255), accentColor2 = Color3.fromRGB(0, 120, 200), }) local Window = self:CreateWindow({ title = "ALib Demo", name = "ALibDemo", theme = "Ocean", size = Vector2.new(580, 460), }) local Main = Window:AddTab("Главная", "🏠") local Combat = Window:AddTab("Бой", "⚔") local sec = Main:AddSection("Основное") sec:AddButton("Тест", function() self:Notification("OK", "Меню работает!", 3, "success") end, { tooltip = "Нажми", description = "test" }) sec:AddToggle("ESP", false, function(v) print("[ALib] ESP:", v) end) sec:AddSlider("FOV", 60, 120, 90, function(v) end) sec:AddDropdown("Режим", { "Legit", "Rage" }, "Legit", function(v) end) sec:AddColorpicker("Цвет", Color3.fromRGB(255, 80, 80), function() end) sec:AddBind("Аим", Enum.KeyCode.E, function(s) print("[ALib] Hold:", s) end, { mode = "hold" }) Combat:AddSection("Аим"):AddToggle("Silent", false, function() end) self:CreateWatermark("ALib v" .. self.Version, { showFps = true, showTime = true }) Window:Build() self:LoadConfig() self:Notification("ALib", "Меню загружено! RightShift — скрыть/показать", 5, "success") local UIS = game:GetService("UserInputService") UIS.InputBegan:Connect(function(input, processed) if processed then return end if input.KeyCode == Enum.KeyCode.RightShift then self:Toggle() end end) print("[ALib] Demo ready. RightShift = toggle menu.") return Window end return Library