local TweenService = game:GetService("TweenService") local UserInputService = game:GetService("UserInputService") local TextService = game:GetService("TextService") local HttpService = game:GetService("HttpService") local Players = game:GetService("Players") local CoreGui = game:GetService("CoreGui") local ContentProvider = game:GetService("ContentProvider") local RunService = game:GetService("RunService") local function PickFont(name, fallback) local ok, font = pcall(function() return Enum.Font[name] end) return (ok and font) or fallback end local WHITE = Color3.fromRGB(255, 255, 255) local Theme = { BackgroundTop = Color3.fromRGB(24, 20, 42), BackgroundBottom = Color3.fromRGB(12, 11, 21), SidebarTop = Color3.fromRGB(29, 24, 50), SidebarBottom = Color3.fromRGB(17, 14, 30), Surface = Color3.fromRGB(31, 27, 50), SurfaceHover = Color3.fromRGB(40, 35, 64), SurfaceActive = Color3.fromRGB(49, 43, 78), Field = Color3.fromRGB(19, 16, 33), Accent = Color3.fromRGB(124, 58, 237), AccentMid = Color3.fromRGB(147, 83, 245), AccentLight = Color3.fromRGB(167, 139, 250), AccentEnd = Color3.fromRGB(192, 132, 252), AccentDark = Color3.fromRGB(76, 29, 149), Text = Color3.fromRGB(246, 244, 255), TextSecondary = Color3.fromRGB(167, 160, 199), TextMuted = Color3.fromRGB(112, 106, 146), Border = Color3.fromRGB(54, 48, 84), BorderHover = Color3.fromRGB(104, 86, 166), TrafficClose = Color3.fromRGB(255, 95, 86), TrafficMinimize = Color3.fromRGB(255, 189, 46), TrafficMaximize = Color3.fromRGB(39, 201, 63), Success = Color3.fromRGB(52, 211, 153), Error = Color3.fromRGB(248, 113, 113), Warning = Color3.fromRGB(251, 191, 36), Info = Color3.fromRGB(167, 139, 250), Font = { Regular = PickFont("BuilderSans", Enum.Font.Gotham), Medium = PickFont("BuilderSansMedium", Enum.Font.GothamMedium), Bold = PickFont("BuilderSansBold", Enum.Font.GothamBold), }, } local AccentSeq = ColorSequence.new(Theme.Accent, Theme.AccentEnd) local function New(class, props, children) local inst = Instance.new(class) local parent for key, value in pairs(props or {}) do if key == "Parent" then parent = value else inst[key] = value end end if children then for _, child in ipairs(children) do child.Parent = inst end end if parent then inst.Parent = parent end return inst end local function Corner(parent, radius) return New("UICorner", { CornerRadius = UDim.new(0, radius), Parent = parent }) end local function Stroke(parent, color, thickness, transparency) return New("UIStroke", { Color = color or Theme.Border, Thickness = thickness or 1, Transparency = transparency or 0, ApplyStrokeMode = Enum.ApplyStrokeMode.Border, Parent = parent, }) end local function Gradient(parent, colors, rotation, transparency) return New("UIGradient", { Color = colors, Rotation = rotation or 0, Transparency = transparency or NumberSequence.new(0), Parent = parent, }) end local TweenInfoCache = {} local function GetTweenInfo(duration, style, direction) local byStyle = TweenInfoCache[style] if not byStyle then byStyle = {} TweenInfoCache[style] = byStyle end local byDirection = byStyle[direction] if not byDirection then byDirection = {} byStyle[direction] = byDirection end local info = byDirection[duration] if not info then info = TweenInfo.new(duration, style, direction) byDirection[duration] = info end return info end local function Tween(obj, duration, props, style, direction) local info = GetTweenInfo( duration or 0.2, style or Enum.EasingStyle.Quint, direction or Enum.EasingDirection.Out ) local tween = TweenService:Create(obj, info, props) tween:Play() return tween end local function NewMaid() local jobs = {} local maid = {} function maid:Give(item) table.insert(jobs, item) return item end function maid:Clean() for _, item in ipairs(jobs) do local kind = typeof(item) if kind == "RBXScriptConnection" then item:Disconnect() elseif kind == "Instance" then item:Destroy() elseif kind == "function" then pcall(item) end end table.clear(jobs) end return maid end local function Env() return (getgenv and getgenv()) or _G end local function Mount(gui) local env = Env() if env.syn and env.syn.protect_gui then pcall(env.syn.protect_gui, gui) end if type(env.gethui) == "function" then local ok, result = pcall(env.gethui) if ok and typeof(result) == "Instance" then gui.Parent = result return end end local ok = pcall(function() gui.Parent = CoreGui end) if ok and gui.Parent then return end local player = Players.LocalPlayer if player then gui.Parent = player:FindFirstChildOfClass("PlayerGui") or player:WaitForChild("PlayerGui", 5) end end local function IsPress(input) return input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch end local ActiveDrags = {} local function StopAllDrags() local pending = {} for stop in pairs(ActiveDrags) do table.insert(pending, stop) end for _, stop in ipairs(pending) do stop() end end local function TrackDrag(startInput, onMove, onEnd) local moveConn, endConn, frameConn local latest local function stop() ActiveDrags[stop] = nil if moveConn then moveConn:Disconnect() moveConn = nil end if frameConn then frameConn:Disconnect() frameConn = nil end if endConn then endConn:Disconnect() endConn = nil end end local function flush() if latest then local position = latest latest = nil onMove(position) end end ActiveDrags[stop] = true moveConn = UserInputService.InputChanged:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch then latest = input.Position end end) frameConn = RunService.RenderStepped:Connect(flush) endConn = UserInputService.InputEnded:Connect(function(input) if input == startInput or input.UserInputType == Enum.UserInputType.MouseButton1 then flush() stop() if onEnd then onEnd() end end end) return stop end local function ClampDelta(target, bounds, startAbs, delta) local minX, minY = bounds.AbsolutePosition.X, bounds.AbsolutePosition.Y local maxX = math.max(minX, minX + bounds.AbsoluteSize.X - target.AbsoluteSize.X) local maxY = math.max(minY, minY + bounds.AbsoluteSize.Y - target.AbsoluteSize.Y) local x = math.max(minX, math.min(maxX, startAbs.X + delta.X)) local y = math.max(minY, math.min(maxY, startAbs.Y + delta.Y)) return Vector2.new(x - startAbs.X, y - startAbs.Y) end local function MakeDraggable(handle, target) handle.Active = true handle.InputBegan:Connect(function(input) if not IsPress(input) then return end local startPos = input.Position local origin = target.Position local startAbs = target.AbsolutePosition local bounds = target.Parent local bounded = bounds ~= nil and bounds:IsA("GuiBase2d") TrackDrag(input, function(pos) local d = pos - startPos if bounded then d = ClampDelta(target, bounds, startAbs, d) end target.Position = UDim2.new(origin.X.Scale, origin.X.Offset + d.X, origin.Y.Scale, origin.Y.Offset + d.Y) end) end) end local function Fire(callback, ...) if not callback then return end local args = table.pack(...) task.spawn(function() local ok, err = pcall(callback, table.unpack(args, 1, args.n)) if not ok then warn("[Excalibur] erro no callback: " .. tostring(err)) end end) end local function ToHex(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 FromHex(text) local hex = tostring(text):gsub("#", ""):gsub("%s", "") if #hex == 3 then hex = hex:sub(1, 1):rep(2) .. hex:sub(2, 2):rep(2) .. hex:sub(3, 3):rep(2) end if #hex ~= 6 or hex:find("%X") then return nil end return Color3.fromRGB(tonumber(hex:sub(1, 2), 16), tonumber(hex:sub(3, 4), 16), tonumber(hex:sub(5, 6), 16)) end local function DecimalsOf(step) local fraction = tostring(step):match("%.(%d+)") return fraction and #fraction or 0 end local function Bar(parent, w, h, rotation, color, cx, cy) return New("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(cx or 0.5, 0, cy or 0.5, 0), Size = UDim2.new(w, 0, h, 0), Rotation = rotation or 0, BackgroundColor3 = color, BorderSizePixel = 0, Parent = parent, }, { New("UICorner", { CornerRadius = UDim.new(1, 0) }) }) end local function Chevron(parent, color) local holder = New("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Size = UDim2.fromOffset(12, 12), BackgroundTransparency = 1, Parent = parent, }) local a = Bar(holder, 0.62, 0.17, 45, color, 0.3, 0.5) local b = Bar(holder, 0.62, 0.17, -45, color, 0.7, 0.5) return holder, function(c) a.BackgroundColor3 = c b.BackgroundColor3 = c end end local function CheckMark(parent, color) local holder = New("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Size = UDim2.fromOffset(14, 14), BackgroundTransparency = 1, Parent = parent, }) Bar(holder, 0.36, 0.14, 45, color, 0.3, 0.64) Bar(holder, 0.72, 0.14, -45, color, 0.58, 0.5) return holder end local function Trim(text) return (tostring(text):gsub("^%s+", ""):gsub("%s+$", "")) end local function NormalizeIcon(icon) if icon == nil or icon == "" then return nil end if type(icon) == "number" then return "rbxassetid://" .. icon end icon = tostring(icon) if icon:match("^%d+$") then return "rbxassetid://" .. icon end if icon:find("^rbxassetid://") or icon:find("^rbxasset://") or icon:find("^rbxthumb://") then return icon end return nil end local function ParentFolder(path) return path:match("^(.*)/[^/]+$") end local function ReadFile(path) local env = Env() if not (env.readfile and env.isfile) then return nil end local ok, content = pcall(function() if env.isfile(path) then return env.readfile(path) end return nil end) if ok then return content end return nil end local function WriteFile(path, content) local env = Env() if not env.writefile then return false end local folder = ParentFolder(path) if folder and env.makefolder and env.isfolder and not env.isfolder(folder) then pcall(env.makefolder, folder) end return (pcall(env.writefile, path, content)) end local function DeleteFile(path) local env = Env() if not (env.delfile and env.isfile) then return false end return (pcall(function() if env.isfile(path) then env.delfile(path) end end)) end local DefaultIcon = nil local Logo = {} Logo.__index = Logo function Logo.new(parent, size, radius, title, icon) local self = setmetatable({}, Logo) self._token = 0 self.Frame = New("Frame", { Size = UDim2.fromOffset(size, size), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = parent, }) Corner(self.Frame, radius) Gradient(self.Frame, ColorSequence.new(Theme.Accent, Theme.AccentEnd), 45) Stroke(self.Frame, WHITE, 1, 0.8) self.Letter = New("TextLabel", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Text = tostring(title or "E"):sub(1, 1):upper(), Font = Theme.Font.Bold, TextSize = math.floor(size * 0.52), TextColor3 = WHITE, Parent = self.Frame, }) self.Image = New("ImageLabel", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, ScaleType = Enum.ScaleType.Crop, Visible = false, Parent = self.Frame, }) Corner(self.Image, radius) self:SetIcon(icon or DefaultIcon) return self end function Logo:SetTitle(title) self.Letter.Text = tostring(title or "E"):sub(1, 1):upper() end function Logo:SetIcon(icon) self._token = self._token + 1 local token = self._token self.Image.Visible = false self.Letter.Visible = true local id = NormalizeIcon(icon) if not id then return end self.Image.Image = id task.spawn(function() local success = false local preloaded = pcall(function() ContentProvider:PreloadAsync({ self.Image }, function(_, status) if status == Enum.AssetFetchStatus.Success then success = true end end) end) if not preloaded then local waited = 0 while self.Image.Parent and not self.Image.IsLoaded and waited < 3 do waited = waited + task.wait(0.1) end success = self.Image.IsLoaded end if token ~= self._token or not self.Image.Parent then return end if success then self.Image.Visible = true self.Letter.Visible = false end end) end local function BuildChrome(parent) local shadow = New("ImageLabel", { Name = "Shadow", AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.new(1, 60, 1, 60), BackgroundTransparency = 1, Image = "rbxassetid://5554236805", ImageColor3 = Color3.fromRGB(8, 4, 24), ImageTransparency = 0.3, ScaleType = Enum.ScaleType.Slice, SliceCenter = Rect.new(23, 23, 277, 277), Parent = parent, }) local main = New("Frame", { Name = "Main", Size = UDim2.fromScale(1, 1), BackgroundColor3 = WHITE, BorderSizePixel = 0, ClipsDescendants = true, Parent = parent, }) Corner(main, 12) Gradient(main, ColorSequence.new(Theme.BackgroundTop, Theme.BackgroundBottom), 125) local stroke = Stroke(main, WHITE, 1, 0) Gradient(stroke, ColorSequence.new(Color3.fromRGB(122, 100, 196), Color3.fromRGB(42, 38, 68)), 90) return shadow, main end local function TrafficLights(parent, interactive) local lights = New("Frame", { Name = "TrafficLights", Position = UDim2.new(0, 16, 0.5, -7), Size = UDim2.fromOffset(64, 14), BackgroundTransparency = 1, Parent = parent, }) local hoverCount = 0 local glyphs = {} local function refresh() task.defer(function() for _, glyph in ipairs(glyphs) do glyph.Visible = hoverCount > 0 end end) end local function dot(x, color, draw, active) local button = New("TextButton", { Position = UDim2.new(0, x, 0.5, -6), Size = UDim2.fromOffset(13, 13), BackgroundColor3 = active and color or Theme.SurfaceActive, AutoButtonColor = false, Text = "", BorderSizePixel = 0, Parent = lights, }) Corner(button, 7) Stroke(button, Color3.new(0, 0, 0), 1, 0.82) if active then local glyph = New("Frame", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Visible = false, Parent = button, }) draw(glyph) table.insert(glyphs, glyph) button.MouseEnter:Connect(function() hoverCount = hoverCount + 1 refresh() end) button.MouseLeave:Connect(function() hoverCount = math.max(hoverCount - 1, 0) refresh() end) end return button end local close = dot(0, Theme.TrafficClose, function(g) local c = Color3.fromRGB(90, 12, 8) Bar(g, 0.62, 0.16, 45, c) Bar(g, 0.62, 0.16, -45, c) end, true) local minimize = dot(20, Theme.TrafficMinimize, function(g) Bar(g, 0.6, 0.16, 0, Color3.fromRGB(105, 62, 0)) end, interactive) local maximize = dot(40, Theme.TrafficMaximize, function(g) local c = Color3.fromRGB(8, 72, 14) Bar(g, 0.6, 0.16, 0, c) Bar(g, 0.6, 0.16, 90, c) end, interactive) return lights, close, minimize, maximize end local function Switch(parent, width, height, state) local knobSize = height - 6 local frame = New("Frame", { AnchorPoint = Vector2.new(1, 0.5), Size = UDim2.fromOffset(width, height), BackgroundColor3 = Theme.Field, BorderSizePixel = 0, Parent = parent, }) Corner(frame, height / 2) local stroke = Stroke(frame, Theme.Border, 1, 0) local fill = New("Frame", { Size = UDim2.fromScale(1, 1), BackgroundColor3 = WHITE, BackgroundTransparency = 1, BorderSizePixel = 0, Parent = frame, }) Corner(fill, height / 2) Gradient(fill, AccentSeq, 0) local knob = New("Frame", { AnchorPoint = Vector2.new(0, 0.5), Position = UDim2.new(0, 3, 0.5, 0), Size = UDim2.fromOffset(knobSize, knobSize), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = frame, }) Corner(knob, knobSize / 2) Stroke(knob, Color3.new(0, 0, 0), 1, 0.85) local object = { Frame = frame, State = false } function object:Set(value, animate) local on = value == true self.State = on local position = on and UDim2.new(1, -3, 0.5, 0) or UDim2.new(0, 3, 0.5, 0) local anchor = Vector2.new(on and 1 or 0, 0.5) local transparency = on and 0 or 1 local color = on and Theme.AccentLight or Theme.Border if animate then Tween(knob, 0.28, { Position = position, AnchorPoint = anchor }) Tween(fill, 0.22, { BackgroundTransparency = transparency }) Tween(stroke, 0.22, { Color = color }) else knob.Position = position knob.AnchorPoint = anchor fill.BackgroundTransparency = transparency stroke.Color = color end end object:Set(state, false) return object end local Excalibur = { Theme = Theme, Version = "3.0.0", Windows = {}, KeySystems = {}, } local Notifier = {} Notifier.__index = Notifier local MAX_TOASTS = 5 local sharedNotifier function Notifier.new() local self = setmetatable({}, Notifier) self._counter = 0 self._active = {} self._destroyed = false self._gui = New("ScreenGui", { Name = "Excalibur_Notifications", DisplayOrder = 1000, ResetOnSpawn = false, ZIndexBehavior = Enum.ZIndexBehavior.Sibling, }) self._holder = New("Frame", { Name = "Holder", AnchorPoint = Vector2.new(1, 1), Position = UDim2.new(1, -18, 1, -18), Size = UDim2.new(0.9, 0, 1, -36), BackgroundTransparency = 1, Parent = self._gui, }) New("UISizeConstraint", { MaxSize = Vector2.new(320, math.huge), Parent = self._holder }) New("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, VerticalAlignment = Enum.VerticalAlignment.Bottom, Padding = UDim.new(0, 8), Parent = self._holder, }) Mount(self._gui) return self end function Notifier:Push(config) if self._destroyed then return nil end local title = config.Title or "Excalibur" local content = config.Content or "" local duration = config.Duration or 4 local tint = Theme[config.Type or "Info"] or Theme.Info local camera = workspace.CurrentCamera local width = math.min(320, (camera and camera.ViewportSize.X or 1280) * 0.9) local measured = TextService:GetTextSize(content, 12, Theme.Font.Regular, Vector2.new(width - 64, 1000)) local height = math.max(58, 14 + 18 + measured.Y + 18) self._counter = self._counter + 1 local slot = New("Frame", { Name = "Slot", Size = UDim2.new(1, 0, 0, height), BackgroundTransparency = 1, LayoutOrder = self._counter, Parent = self._holder, }) local card = New("TextButton", { Name = "Notification", Position = UDim2.new(1.2, 0, 0, 0), Size = UDim2.fromScale(1, 1), BackgroundColor3 = Theme.Surface, AutoButtonColor = false, Text = "", BorderSizePixel = 0, Parent = slot, }) Corner(card, 12) Stroke(card, Theme.Border, 1, 0.1) Gradient(card, ColorSequence.new(WHITE, Color3.fromRGB(205, 198, 232)), 90) local badge = New("Frame", { Position = UDim2.new(0, 14, 0, 14), Size = UDim2.fromOffset(26, 26), BackgroundColor3 = tint, BackgroundTransparency = 0.82, BorderSizePixel = 0, Parent = card, }) Corner(badge, 13) local dot = New("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.fromOffset(10, 10), BackgroundColor3 = tint, BorderSizePixel = 0, Parent = badge, }) Corner(dot, 5) New("TextLabel", { Position = UDim2.new(0, 50, 0, 11), Size = UDim2.new(1, -64, 0, 18), BackgroundTransparency = 1, Text = title, Font = Theme.Font.Bold, TextSize = 13, TextColor3 = Theme.Text, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = card, }) New("TextLabel", { Position = UDim2.new(0, 50, 0, 30), Size = UDim2.new(1, -64, 0, measured.Y), BackgroundTransparency = 1, Text = content, Font = Theme.Font.Regular, TextSize = 12, TextColor3 = Theme.TextSecondary, TextWrapped = true, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, Parent = card, }) local bar = New("Frame", { Position = UDim2.new(0, 14, 1, -6), Size = UDim2.new(1, -28, 0, 2), BackgroundColor3 = tint, BackgroundTransparency = 0.35, BorderSizePixel = 0, Parent = card, }) Corner(bar, 1) Tween(card, 0.45, { Position = UDim2.new(0, 0, 0, 0) }) Tween(bar, duration, { Size = UDim2.new(0, 0, 0, 2) }, Enum.EasingStyle.Linear) local dismissed = false local dismiss dismiss = function() if dismissed then return end dismissed = true local index = table.find(self._active, dismiss) if index then table.remove(self._active, index) end if self._destroyed or not card.Parent then return end local out = Tween(card, 0.3, { Position = UDim2.new(1.2, 0, 0, 0) }, Enum.EasingStyle.Quint, Enum.EasingDirection.In) out.Completed:Connect(function() if self._destroyed or not slot.Parent then return end Tween(slot, 0.22, { Size = UDim2.new(1, 0, 0, 0) }).Completed:Connect(function() slot:Destroy() end) end) end card.MouseButton1Click:Connect(dismiss) task.delay(duration, dismiss) table.insert(self._active, dismiss) if #self._active > MAX_TOASTS then self._active[1]() end return { Dismiss = dismiss } end function Notifier:Destroy() if self._destroyed then return end self._destroyed = true table.clear(self._active) self._gui:Destroy() end local function GetNotifier() if not sharedNotifier or sharedNotifier._destroyed or not sharedNotifier._gui.Parent then sharedNotifier = Notifier.new() end return sharedNotifier end function Excalibur:SetDefaultIcon(icon) DefaultIcon = icon end function Excalibur:Notify(config) if type(config) == "string" then config = { Content = config } end return GetNotifier():Push(config or {}) end local function EncodeValue(value) local kind = typeof(value) if kind == "Color3" then return { __c = { value.R, value.G, value.B } } elseif kind == "EnumItem" then return { __k = value.Name } end return value end local function DecodeValue(value) if type(value) == "table" then if value.__c then return Color3.new(value.__c[1], value.__c[2], value.__c[3]) elseif value.__k then local ok, key = pcall(function() return Enum.KeyCode[value.__k] end) return ok and key or nil end end return value end local TabMethods = {} TabMethods.__index = TabMethods local function NextOrder(tab) tab._order = (tab._order or 0) + 1 return tab._order end local CARD_H = 44 local CARD_H_DESC = 54 local function BaseCard(tab, name, height) local card = New("Frame", { Name = name, Size = UDim2.new(1, 0, 0, height), BackgroundColor3 = Theme.Surface, BorderSizePixel = 0, LayoutOrder = NextOrder(tab), }) Corner(card, 10) local stroke = Stroke(card, Theme.Border, 1, 0.2) local gradient = Gradient(card, ColorSequence.new(WHITE, Color3.fromRGB(212, 205, 236)), 90) card.Parent = tab._page return card, stroke, gradient end local function TitleBlock(card, name, desc, reserve, height, topAligned, widthScale) local hasDesc = desc ~= nil and desc ~= "" local top = hasDesc or topAligned local scale = widthScale or 1 local offset = widthScale and -14 or -(28 + reserve) local title = New("TextLabel", { Name = "Title", BackgroundTransparency = 1, Position = UDim2.new(0, 14, 0, top and 8 or 0), Size = UDim2.new(scale, offset, 0, top and 18 or height), Text = name, Font = Theme.Font.Medium, TextSize = 13, TextColor3 = Theme.Text, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = card, }) local descLabel if hasDesc then descLabel = New("TextLabel", { Name = "Description", BackgroundTransparency = 1, Position = UDim2.new(0, 14, 0, 27), Size = UDim2.new(scale, offset, 0, 14), Text = desc, Font = Theme.Font.Regular, TextSize = 11, TextColor3 = Theme.TextSecondary, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = card, }) end return title, descLabel end local function Hover(target, card, stroke) target.MouseEnter:Connect(function() Tween(card, 0.18, { BackgroundColor3 = Theme.SurfaceHover }) Tween(stroke, 0.18, { Color = Theme.BorderHover, Transparency = 0 }) end) target.MouseLeave:Connect(function() Tween(card, 0.18, { BackgroundColor3 = Theme.Surface }) Tween(stroke, 0.18, { Color = Theme.Border, Transparency = 0.2 }) end) end local REVEAL_LIMIT = 8 local function RevealRows(options, rows) local step = 0 for _, option in ipairs(options) do local row = rows[option] if row then step = step + 1 if step > REVEAL_LIMIT then return end local label = row.label label.TextTransparency = 1 task.delay(step * 0.025, function() if label.Parent then Tween(label, 0.22, { TextTransparency = 0 }) end end) end end end local function Emitter(tab, cfg) local window = tab._window return function(value) if cfg.Flag then window.Flags[cfg.Flag] = value end Fire(cfg.Callback, value) end end local function Register(tab, cfg, object) if cfg.Flag then tab._window.Elements[cfg.Flag] = object tab._window.Flags[cfg.Flag] = object:GetValue() end end local function PillField(parent, width, minWidth, maxWidth) local scaled = width <= 1 local pill = New("Frame", { AnchorPoint = Vector2.new(1, 0.5), Size = scaled and UDim2.new(width, 0, 0, 26) or UDim2.fromOffset(width, 26), BackgroundColor3 = Theme.Field, BorderSizePixel = 0, Parent = parent, }) Corner(pill, 7) if scaled then New("UISizeConstraint", { MinSize = Vector2.new(minWidth or 90, 26), MaxSize = Vector2.new(maxWidth or 170, 26), Parent = pill, }) end local stroke = Stroke(pill, Theme.Border, 1, 0.1) return pill, stroke end local function Destroyable(object, card, tab, kind, name, desc) local item = { frame = card, kind = kind or "element", name = name and tostring(name) or "", desc = desc and tostring(desc) or "", hidden = false, matched = true, } table.insert(tab._items, item) function object:Destroy() local index = table.find(tab._items, item) if index then table.remove(tab._items, index) end card:Destroy() end function object:SetVisible(state) item.hidden = not state card.Visible = state and item.matched end return object end local function AttachTooltip(tab, card, text) if text == nil or text == "" then return end local window = tab._window local title = card:FindFirstChild("Title") local textWidth = 0 local centerY = 22 if title then local bounds = TextService:GetTextSize(title.Text, 13, Theme.Font.Medium, Vector2.new(1000, 100)) textWidth = math.min(bounds.X, 150) centerY = title.Position.Y.Offset + title.Size.Y.Offset / 2 end local icon = New("TextButton", { Name = "Help", AnchorPoint = Vector2.new(0, 0.5), Position = UDim2.new(0, 14 + textWidth + 8, 0, centerY), Size = UDim2.fromOffset(15, 15), BackgroundColor3 = Theme.Field, AutoButtonColor = false, Text = "?", Font = Theme.Font.Bold, TextSize = 10, TextColor3 = Theme.TextMuted, BorderSizePixel = 0, ZIndex = 6, Parent = card, }) Corner(icon, 8) Stroke(icon, Theme.Border, 1, 0.1) icon.MouseEnter:Connect(function() Tween(icon, 0.15, { TextColor3 = Theme.AccentLight, BackgroundColor3 = Theme.SurfaceHover }) if UserInputService.MouseEnabled then window:ShowTooltip(icon, text) end end) icon.MouseLeave:Connect(function() Tween(icon, 0.15, { TextColor3 = Theme.TextMuted, BackgroundColor3 = Theme.Field }) if UserInputService.MouseEnabled then window:HideTooltip(icon) end end) icon.MouseButton1Click:Connect(function() window:ToggleTooltip(icon, text) end) end function TabMethods:CreateSection(cfg) local name = type(cfg) == "string" and cfg or (cfg.Name or "Section") local holder = New("Frame", { Name = "Section_" .. name, Size = UDim2.new(1, 0, 0, 30), BackgroundTransparency = 1, LayoutOrder = NextOrder(self), Parent = self._page, }) local pill = New("Frame", { Position = UDim2.new(0, 2, 1, -21), Size = UDim2.fromOffset(3, 14), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = holder, }) Corner(pill, 2) Gradient(pill, AccentSeq, 90) local label = New("TextLabel", { Position = UDim2.new(0, 14, 1, -24), Size = UDim2.new(1, -14, 0, 20), BackgroundTransparency = 1, Text = name, Font = Theme.Font.Bold, TextSize = 13, TextColor3 = Theme.AccentLight, TextXAlignment = Enum.TextXAlignment.Left, Parent = holder, }) local object = {} function object:SetText(text) label.Text = text end return Destroyable(object, holder, self, "section", name, nil) end function TabMethods:CreateDivider() local holder = New("Frame", { Name = "Divider", Size = UDim2.new(1, 0, 0, 10), BackgroundTransparency = 1, LayoutOrder = NextOrder(self), Parent = self._page, }) local line = New("Frame", { AnchorPoint = Vector2.new(0, 0.5), Position = UDim2.fromScale(0, 0.5), Size = UDim2.new(1, 0, 0, 1), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = holder, }) Gradient( line, ColorSequence.new(Theme.Border, Theme.Border), 0, NumberSequence.new({ NumberSequenceKeypoint.new(0, 0.2), NumberSequenceKeypoint.new(1, 1), }) ) return Destroyable({}, holder, self, "divider", nil, nil) end function TabMethods:CreateLabel(cfg) if type(cfg) == "string" then cfg = { Text = cfg } end local desc = cfg.Description local height = (desc and desc ~= "") and CARD_H_DESC or 38 local card = BaseCard(self, "Label", height) local title, descLabel = TitleBlock(card, cfg.Text or cfg.Name or "Label", desc, 0, height) AttachTooltip(self, card, cfg.Tooltip) title.Font = Theme.Font.Medium local object = {} function object:SetText(text) title.Text = text end function object:SetDescription(text) if descLabel then descLabel.Text = text end end return Destroyable(object, card, self, "label", (cfg.Text or cfg.Name or "Label"), desc) end function TabMethods:CreateParagraph(cfg) local card = BaseCard(self, "Paragraph", 0) card.AutomaticSize = Enum.AutomaticSize.Y card.Size = UDim2.new(1, 0, 0, 0) New("UIPadding", { PaddingTop = UDim.new(0, 12), PaddingBottom = UDim.new(0, 12), PaddingLeft = UDim.new(0, 14), PaddingRight = UDim.new(0, 14), Parent = card, }) New("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 4), Parent = card }) local title = New("TextLabel", { LayoutOrder = 1, AutomaticSize = Enum.AutomaticSize.Y, Size = UDim2.new(1, 0, 0, 0), BackgroundTransparency = 1, Text = cfg.Title or "", Font = Theme.Font.Bold, TextSize = 13, TextColor3 = Theme.Text, TextWrapped = true, TextXAlignment = Enum.TextXAlignment.Left, Visible = (cfg.Title ~= nil and cfg.Title ~= ""), Parent = card, }) local body = New("TextLabel", { LayoutOrder = 2, AutomaticSize = Enum.AutomaticSize.Y, Size = UDim2.new(1, 0, 0, 0), BackgroundTransparency = 1, Text = cfg.Content or "", Font = Theme.Font.Regular, TextSize = 12, TextColor3 = Theme.TextSecondary, TextWrapped = true, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, Parent = card, }) local object = {} function object:SetTitle(text) title.Text = text title.Visible = text ~= "" end function object:SetContent(text) body.Text = text end return Destroyable(object, card, self, "paragraph", cfg.Title, cfg.Content) end function TabMethods:CreateButton(cfg) local name = cfg.Name or "Button" local desc = cfg.Description local primary = cfg.Style == "Primary" local height = (desc and desc ~= "") and CARD_H_DESC or CARD_H local card, stroke, gradient = BaseCard(self, "Button_" .. name, height) local title, descLabel = TitleBlock(card, name, desc, 28, height) AttachTooltip(self, card, cfg.Tooltip) local arrowHolder, setArrow = Chevron(card, Theme.TextMuted) arrowHolder.Position = UDim2.new(1, -22, 0.5, 0) arrowHolder.Rotation = -90 if primary then card.BackgroundColor3 = WHITE gradient.Color = ColorSequence.new(Theme.Accent, Theme.AccentEnd) gradient.Rotation = 0 stroke.Color = Theme.AccentLight stroke.Transparency = 0.5 title.Font = Theme.Font.Bold setArrow(WHITE) if descLabel then descLabel.TextColor3 = Color3.fromRGB(233, 223, 255) end end local scale = New("UIScale", { Parent = card }) local hit = New("TextButton", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Text = "", ZIndex = 3, Parent = card, }) if not primary then Hover(hit, card, stroke) end hit.MouseEnter:Connect(function() if not primary then Tween(arrowHolder, 0.2, { Position = UDim2.new(1, -18, 0.5, 0) }) setArrow(Theme.AccentLight) else Tween(stroke, 0.2, { Transparency = 0 }) end end) hit.MouseLeave:Connect(function() if not primary then Tween(arrowHolder, 0.2, { Position = UDim2.new(1, -22, 0.5, 0) }) setArrow(Theme.TextMuted) else Tween(stroke, 0.2, { Transparency = 0.5 }) end Tween(scale, 0.15, { Scale = 1 }) end) hit.MouseButton1Down:Connect(function() Tween(scale, 0.1, { Scale = 0.985 }, Enum.EasingStyle.Quad) end) hit.MouseButton1Up:Connect(function() Tween(scale, 0.2, { Scale = 1 }) end) hit.MouseButton1Click:Connect(function() Fire(cfg.Callback) end) local object = {} function object:SetText(text) title.Text = text end function object:SetDescription(text) if descLabel then descLabel.Text = text end end function object:Fire() Fire(cfg.Callback) end return Destroyable(object, card, self, "element", name, desc) end function TabMethods:CreateToggle(cfg) local name = cfg.Name or "Toggle" local desc = cfg.Description local state = cfg.Default == true local emit = Emitter(self, cfg) local height = (desc and desc ~= "") and CARD_H_DESC or CARD_H local card, stroke = BaseCard(self, "Toggle_" .. name, height) TitleBlock(card, name, desc, 56, height) AttachTooltip(self, card, cfg.Tooltip) local switch = New("Frame", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -14, 0.5, 0), Size = UDim2.fromOffset(42, 24), BackgroundColor3 = Theme.Field, BorderSizePixel = 0, Parent = card, }) Corner(switch, 12) local switchStroke = Stroke(switch, Theme.Border, 1, 0) local fill = New("Frame", { Size = UDim2.fromScale(1, 1), BackgroundColor3 = WHITE, BackgroundTransparency = 1, BorderSizePixel = 0, Parent = switch, }) Corner(fill, 12) Gradient(fill, AccentSeq, 0) local knob = New("Frame", { AnchorPoint = Vector2.new(0, 0.5), Position = UDim2.new(0, 3, 0.5, 0), Size = UDim2.fromOffset(18, 18), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = switch, }) Corner(knob, 9) Stroke(knob, Color3.new(0, 0, 0), 1, 0.85) local function render(animate) local props = { Position = state and UDim2.new(1, -3, 0.5, 0) or UDim2.new(0, 3, 0.5, 0), AnchorPoint = Vector2.new(state and 1 or 0, 0.5), Size = UDim2.fromOffset(18, 18), } local fillT = state and 0 or 1 local strokeColor = state and Theme.AccentLight or Theme.Border if animate then Tween(knob, 0.3, props) Tween(fill, 0.25, { BackgroundTransparency = fillT }) Tween(switchStroke, 0.25, { Color = strokeColor }) else knob.Position, knob.AnchorPoint, knob.Size = props.Position, props.AnchorPoint, props.Size fill.BackgroundTransparency = fillT switchStroke.Color = strokeColor end end render(false) local hit = New("TextButton", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Text = "", ZIndex = 3, Parent = card, }) Hover(hit, card, stroke) hit.MouseButton1Down:Connect(function() Tween(knob, 0.12, { Size = UDim2.fromOffset(23, 18) }) end) hit.MouseButton1Click:Connect(function() state = not state render(true) emit(state) end) hit.MouseLeave:Connect(function() Tween(knob, 0.15, { Size = UDim2.fromOffset(18, 18) }) end) local object = {} function object:Set(value) value = value == true if value == state then return end state = value render(true) emit(state) end function object:GetValue() return state end Register(self, cfg, object) return Destroyable(object, card, self, "element", name, desc) end function TabMethods:CreateSlider(cfg) local name = cfg.Name or "Slider" local desc = cfg.Description local minV = cfg.Min or 0 local maxV = cfg.Max or 100 local step = cfg.Step or 1 local precision = cfg.Precision or DecimalsOf(step) local suffix = cfg.Suffix and (" " .. cfg.Suffix) or "" local emit = Emitter(self, cfg) local hasDesc = desc ~= nil and desc ~= "" local height = hasDesc and 68 or 58 local function snap(v) v = math.clamp(v, minV, maxV) v = math.floor((v - minV) / step + 0.5) * step + minV local mult = 10 ^ precision return math.clamp(math.floor(v * mult + 0.5) / mult, minV, maxV) end local function format(v) return string.format("%." .. precision .. "f", v) end local value = snap(cfg.Default or minV) local card, stroke = BaseCard(self, "Slider_" .. name, height) TitleBlock(card, name, desc, 100, height, true) AttachTooltip(self, card, cfg.Tooltip) Hover(card, card, stroke) local valueBox = New("TextBox", { AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, -14, 0, 7), Size = UDim2.fromOffset(82, 21), BackgroundColor3 = Theme.Field, BorderSizePixel = 0, ClearTextOnFocus = false, Font = Theme.Font.Bold, TextSize = 11, TextColor3 = Theme.AccentLight, Text = format(value) .. suffix, Parent = card, }) Corner(valueBox, 6) local boxStroke = Stroke(valueBox, Theme.Border, 1, 0.1) local hit = New("TextButton", { Name = "Hit", Position = UDim2.new(0, 14, 1, -26), Size = UDim2.new(1, -28, 0, 20), BackgroundTransparency = 1, Text = "", AutoButtonColor = false, Parent = card, }) local bar = New("Frame", { AnchorPoint = Vector2.new(0, 0.5), Position = UDim2.new(0, 0, 0.5, 0), Size = UDim2.new(1, 0, 0, 6), BackgroundColor3 = Theme.Field, BorderSizePixel = 0, Parent = hit, }) Corner(bar, 3) Stroke(bar, Theme.Border, 1, 0.3) local pct = (value - minV) / math.max(maxV - minV, 1e-9) local fill = New("Frame", { Size = UDim2.new(pct, 0, 1, 0), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = bar, }) Corner(fill, 3) Gradient(fill, AccentSeq, 0) local thumb = New("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(pct, 0, 0.5, 0), Size = UDim2.fromOffset(16, 16), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = bar, }) Corner(thumb, 8) local thumbStroke = Stroke(thumb, Theme.AccentLight, 2, 0.35) local function apply(v, mode, silent) v = snap(v) local changed = v ~= value value = v local p = (v - minV) / math.max(maxV - minV, 1e-9) if mode == "smooth" then Tween(fill, 0.2, { Size = UDim2.new(p, 0, 1, 0) }) Tween(thumb, 0.2, { Position = UDim2.new(p, 0, 0.5, 0) }) else fill.Size = UDim2.new(p, 0, 1, 0) thumb.Position = UDim2.new(p, 0, 0.5, 0) end valueBox.Text = format(v) .. suffix if changed and not silent then emit(v) end end local function fromX(x) local ax, aw = bar.AbsolutePosition.X, bar.AbsoluteSize.X return minV + (maxV - minV) * math.clamp((x - ax) / math.max(aw, 1), 0, 1) end hit.InputBegan:Connect(function(input) if not IsPress(input) then return end self._page.ScrollingEnabled = false Tween(thumb, 0.12, { Size = UDim2.fromOffset(19, 19) }) Tween(thumbStroke, 0.12, { Transparency = 0 }) apply(fromX(input.Position.X)) TrackDrag(input, function(pos) apply(fromX(pos.X)) end, function() self._page.ScrollingEnabled = true Tween(thumb, 0.15, { Size = UDim2.fromOffset(16, 16) }) Tween(thumbStroke, 0.15, { Transparency = 0.35 }) end) end) valueBox.Focused:Connect(function() valueBox.Text = format(value) Tween(boxStroke, 0.15, { Color = Theme.AccentLight, Transparency = 0 }) end) valueBox.FocusLost:Connect(function() Tween(boxStroke, 0.15, { Color = Theme.Border, Transparency = 0.1 }) local number = tonumber(valueBox.Text:match("-?%d+%.?%d*")) if number then apply(number, "smooth") end valueBox.Text = format(value) .. suffix end) local object = {} function object:Set(v) apply(v, "smooth") end function object:GetValue() return value end Register(self, cfg, object) return Destroyable(object, card, self, "element", name, desc) end function TabMethods:CreateDropdown(cfg) local name = cfg.Name or "Dropdown" local desc = cfg.Description local options = cfg.Options or {} local multi = cfg.Multi == true local emit = Emitter(self, cfg) local hasDesc = desc ~= nil and desc ~= "" local headerH = hasDesc and CARD_H_DESC or CARD_H local isOpen = false local states = {} local single = nil local rows = {} local function assign(value) states = {} single = nil if multi then if type(value) == "table" then for key, entry in pairs(value) do if type(key) == "number" then states[entry] = true elseif entry == true then states[key] = true end end elseif type(value) == "string" then states[value] = true end else single = type(value) == "string" and value or nil end end assign(cfg.Default) local function isSelected(option) if multi then return states[option] == true end return single == option end local function snapshot() if not multi then return single end local result = {} for _, option in ipairs(options) do result[option] = states[option] == true end return result end local function display() if not multi then return single or "Select..." end local chosen = {} for _, option in ipairs(options) do if states[option] then table.insert(chosen, option) end end if #chosen == 0 then return "None" elseif #chosen <= 2 then return table.concat(chosen, ", ") end return #chosen .. " selected" end local card, stroke = BaseCard(self, "Dropdown_" .. name, headerH) card.ClipsDescendants = true TitleBlock(card, name, desc, 0, headerH, false, 0.5) AttachTooltip(self, card, cfg.Tooltip) local header = New("TextButton", { Size = UDim2.new(1, 0, 0, headerH), BackgroundTransparency = 1, Text = "", ZIndex = 3, Parent = card, }) Hover(header, card, stroke) local pill = PillField(card, 0.36, 84, 160) pill.Position = UDim2.new(1, -38, 0, headerH / 2) local pillLabel = New("TextLabel", { Position = UDim2.new(0, 10, 0, 0), Size = UDim2.new(1, -20, 1, 0), BackgroundTransparency = 1, Font = Theme.Font.Medium, TextSize = 12, TextColor3 = Theme.AccentLight, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = pill, }) local chevron = Chevron(card, Theme.TextMuted) chevron.Position = UDim2.new(1, -22, 0, headerH / 2) local list = New("ScrollingFrame", { Position = UDim2.new(0, 10, 0, headerH + 4), Size = UDim2.new(1, -20, 0, 0), BackgroundTransparency = 1, BorderSizePixel = 0, ScrollBarThickness = 2, ScrollBarImageColor3 = Theme.Accent, CanvasSize = UDim2.new(), AutomaticCanvasSize = Enum.AutomaticSize.Y, Parent = card, }) New("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 2), Parent = list }) local function paint(animate) for option, row in pairs(rows) do local on = isSelected(option) Tween(row.label, 0.15, { TextColor3 = on and Theme.Text or Theme.TextSecondary }) if multi then row.switch:Set(on, animate) else Tween(row.button, 0.15, { BackgroundTransparency = on and 0.35 or 1 }) row.check.Visible = on end end pillLabel.Text = display() end local function listHeight() return math.max(math.min(#options * 30 - 2, 150), 0) end local function setOpen(state) isOpen = state local height = listHeight() Tween(card, 0.34, { Size = UDim2.new(1, 0, 0, state and (headerH + height + 14) or headerH) }) Tween(list, 0.34, { Size = UDim2.new(1, -20, 0, state and height or 0) }) Tween(chevron, 0.3, { Rotation = state and 180 or 0 }) Tween(stroke, 0.3, { Color = state and Theme.BorderHover or Theme.Border }) if state then RevealRows(options, rows) end end local function choose(option) if multi then states[option] = (not states[option]) or nil paint(true) emit(snapshot()) else single = option paint(true) setOpen(false) emit(single) end end local function build() for _, row in pairs(rows) do row.button:Destroy() end rows = {} for index, option in ipairs(options) do local button = New("TextButton", { Name = "Option_" .. option, Size = UDim2.new(1, -4, 0, 28), BackgroundColor3 = Theme.AccentDark, BackgroundTransparency = 1, AutoButtonColor = false, Text = "", LayoutOrder = index, Parent = list, }) Corner(button, 7) local label = New("TextLabel", { Position = UDim2.new(0, 10, 0, 0), Size = UDim2.new(1, multi and -56 or -36, 1, 0), BackgroundTransparency = 1, Text = option, Font = Theme.Font.Medium, TextSize = 12, TextColor3 = Theme.TextSecondary, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = button, }) local row = { button = button, label = label } if multi then row.switch = Switch(button, 30, 16, states[option] == true) row.switch.Frame.Position = UDim2.new(1, -8, 0.5, 0) else row.check = CheckMark(button, Theme.AccentLight) row.check.Position = UDim2.new(1, -16, 0.5, 0) row.check.Visible = false end button.MouseEnter:Connect(function() if multi or not isSelected(option) then Tween(button, 0.12, { BackgroundTransparency = 0.7 }) end end) button.MouseLeave:Connect(function() if multi or not isSelected(option) then Tween(button, 0.12, { BackgroundTransparency = 1 }) end end) button.MouseButton1Click:Connect(function() choose(option) end) rows[option] = row end paint(false) end build() header.MouseButton1Click:Connect(function() setOpen(not isOpen) end) local object = {} function object:Set(value) assign(value) paint(true) emit(snapshot()) end function object:GetValue() return snapshot() end function object:SetOption(option, state) if multi and rows[option] then states[option] = state == true or nil paint(true) emit(snapshot()) end end function object:SelectAll() if multi then for _, option in ipairs(options) do states[option] = true end paint(true) emit(snapshot()) end end function object:ClearAll() if multi then states = {} paint(true) emit(snapshot()) end end function object:Refresh(newOptions, newValue) options = newOptions or {} if newValue ~= nil then assign(newValue) else local kept = {} for _, option in ipairs(options) do if states[option] then kept[option] = true end end states = kept if single and not table.find(options, single) then single = nil end end build() if isOpen then setOpen(true) end end function object:Open() setOpen(true) end function object:Close() setOpen(false) end function object:IsOpen() return isOpen end Register(self, cfg, object) return Destroyable(object, card, self, "element", name, desc) end function TabMethods:CreateSelectToggle(cfg) local name = cfg.Name or "Select and Toggle" local desc = cfg.Description local options = cfg.Options or {} local window = self._window local hasDesc = desc ~= nil and desc ~= "" local headerH = hasDesc and CARD_H_DESC or CARD_H local isOpen = false local enabled = false local states = {} local rows = {} local paint local function readStates(items) local result = {} if type(items) == "table" then for key, entry in pairs(items) do if type(key) == "number" then result[entry] = true elseif entry == true then result[key] = true end end end return result end local function split(value) if type(value) == "table" and (value.Items ~= nil or value.Enabled ~= nil) then return value.Items, value.Enabled end return value, nil end local function copy(source) local result = {} for key, value in pairs(source) do result[key] = value end return result end local initialItems, initialEnabled = split(cfg.Default) states = readStates(initialItems) enabled = initialEnabled == true or cfg.Enabled == true local function snapshot() local items = {} for _, option in ipairs(options) do items[option] = states[option] == true end return items end local function commit() local items = snapshot() if cfg.Flag then window.Flags[cfg.Flag] = { Enabled = enabled, Items = items } end Fire(cfg.Callback, enabled, items) end local function notifyItems(previousStates, previousEnabled) if not cfg.OnItemChanged then return end for _, option in ipairs(options) do local before = previousEnabled and previousStates[option] == true local after = enabled and states[option] == true if before ~= after then Fire(cfg.OnItemChanged, option, after) end end end local function change(newStates, newEnabled) local previousStates, previousEnabled = states, enabled states = newStates enabled = newEnabled paint(true) notifyItems(previousStates, previousEnabled) commit() end local function display() local chosen = {} for _, option in ipairs(options) do if states[option] then table.insert(chosen, option) end end if #chosen == 0 then return "None" elseif #chosen <= 2 then return table.concat(chosen, ", ") end return #chosen .. " selected" end local card, stroke = BaseCard(self, "SelectToggle_" .. name, headerH) card.ClipsDescendants = true TitleBlock(card, name, desc, 0, headerH, false, 0.3) AttachTooltip(self, card, cfg.Tooltip) local header = New("TextButton", { Size = UDim2.new(1, 0, 0, headerH), BackgroundTransparency = 1, Text = "", ZIndex = 3, Parent = card, }) Hover(header, card, stroke) local pill = PillField(card, 0.28, 70, 130) pill.Position = UDim2.new(1, -100, 0, headerH / 2) local pillLabel = New("TextLabel", { Position = UDim2.new(0, 8, 0, 0), Size = UDim2.new(1, -16, 1, 0), BackgroundTransparency = 1, Font = Theme.Font.Medium, TextSize = 12, TextColor3 = Theme.AccentLight, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = pill, }) local master = Switch(card, 42, 24, enabled) master.Frame.Position = UDim2.new(1, -44, 0, headerH / 2) master.Frame.ZIndex = 4 local masterHit = New("TextButton", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Text = "", ZIndex = 5, Parent = master.Frame, }) masterHit.MouseButton1Click:Connect(function() change(states, not enabled) end) local chevron = Chevron(card, Theme.TextMuted) chevron.Position = UDim2.new(1, -22, 0, headerH / 2) local list = New("ScrollingFrame", { Position = UDim2.new(0, 10, 0, headerH + 4), Size = UDim2.new(1, -20, 0, 0), BackgroundTransparency = 1, BorderSizePixel = 0, ScrollBarThickness = 2, ScrollBarImageColor3 = Theme.Accent, CanvasSize = UDim2.new(), AutomaticCanvasSize = Enum.AutomaticSize.Y, Parent = card, }) New("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 2), Parent = list }) local tools = New("Frame", { Size = UDim2.new(1, -4, 0, 26), BackgroundTransparency = 1, LayoutOrder = 0, Parent = list, }) local function tool(text, position, callback) local button = New("TextButton", { Position = position, Size = UDim2.new(0.5, -3, 1, 0), BackgroundColor3 = Theme.Field, AutoButtonColor = false, Text = text, Font = Theme.Font.Medium, TextSize = 11, TextColor3 = Theme.TextSecondary, BorderSizePixel = 0, Parent = tools, }) Corner(button, 7) Stroke(button, Theme.Border, 1, 0.2) button.MouseEnter:Connect(function() Tween(button, 0.12, { BackgroundColor3 = Theme.SurfaceHover, TextColor3 = Theme.Text }) end) button.MouseLeave:Connect(function() Tween(button, 0.12, { BackgroundColor3 = Theme.Field, TextColor3 = Theme.TextSecondary }) end) button.MouseButton1Click:Connect(callback) end tool("Select all", UDim2.new(0, 0, 0, 0), function() local all = {} for _, option in ipairs(options) do all[option] = true end change(all, enabled) end) tool("Clear", UDim2.new(0.5, 3, 0, 0), function() change({}, enabled) end) paint = function(animate) for option, row in pairs(rows) do local on = states[option] == true Tween(row.label, 0.15, { TextColor3 = on and Theme.Text or Theme.TextSecondary }) row.switch:Set(on, animate) end pillLabel.Text = display() Tween(pillLabel, 0.2, { TextColor3 = enabled and Theme.Success or Theme.AccentLight }) master:Set(enabled, animate) end local function setOpen(state) isOpen = state local height = math.min(#options * 30 + 28, 180) Tween(card, 0.34, { Size = UDim2.new(1, 0, 0, state and (headerH + height + 14) or headerH) }) Tween(list, 0.34, { Size = UDim2.new(1, -20, 0, state and height or 0) }) Tween(chevron, 0.3, { Rotation = state and 180 or 0 }) Tween(stroke, 0.3, { Color = state and Theme.BorderHover or Theme.Border }) if state then RevealRows(options, rows) end end local function build() for _, row in pairs(rows) do row.button:Destroy() end rows = {} for index, option in ipairs(options) do local button = New("TextButton", { Name = "Option_" .. option, Size = UDim2.new(1, -4, 0, 28), BackgroundColor3 = Theme.AccentDark, BackgroundTransparency = 1, AutoButtonColor = false, Text = "", LayoutOrder = index, Parent = list, }) Corner(button, 7) local label = New("TextLabel", { Position = UDim2.new(0, 10, 0, 0), Size = UDim2.new(1, -56, 1, 0), BackgroundTransparency = 1, Text = option, Font = Theme.Font.Medium, TextSize = 12, TextColor3 = Theme.TextSecondary, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = button, }) local rowSwitch = Switch(button, 30, 16, states[option] == true) rowSwitch.Frame.Position = UDim2.new(1, -8, 0.5, 0) button.MouseEnter:Connect(function() Tween(button, 0.12, { BackgroundTransparency = 0.7 }) end) button.MouseLeave:Connect(function() Tween(button, 0.12, { BackgroundTransparency = 1 }) end) button.MouseButton1Click:Connect(function() local nextStates = copy(states) nextStates[option] = (not nextStates[option]) or nil change(nextStates, enabled) end) rows[option] = { button = button, label = label, switch = rowSwitch } end paint(false) end build() header.MouseButton1Click:Connect(function() setOpen(not isOpen) end) local object = {} function object:Set(value) local items, newEnabled = split(value) local newStates = type(items) == "table" and readStates(items) or states if newEnabled == nil then newEnabled = enabled end change(newStates, newEnabled == true) end function object:GetValue() return { Enabled = enabled, Items = snapshot() } end function object:SetEnabled(state) change(states, state == true) end function object:IsEnabled() return enabled end function object:IsActive(option) return enabled and states[option] == true end function object:SetOption(option, state) local nextStates = copy(states) nextStates[option] = state == true or nil change(nextStates, enabled) end function object:SelectAll() local all = {} for _, option in ipairs(options) do all[option] = true end change(all, enabled) end function object:ClearAll() change({}, enabled) end function object:Refresh(newOptions, newItems) options = newOptions or {} local kept = {} local source = newItems ~= nil and readStates(newItems) or states for _, option in ipairs(options) do if source[option] then kept[option] = true end end states = kept build() if isOpen then setOpen(true) end commit() end function object:Open() setOpen(true) end function object:Close() setOpen(false) end Register(self, cfg, object) return Destroyable(object, card, self, "element", name, desc) end function TabMethods:CreateTextbox(cfg) local name = cfg.Name or "Textbox" local desc = cfg.Description local emit = Emitter(self, cfg) local hasDesc = desc ~= nil and desc ~= "" local height = hasDesc and CARD_H_DESC or CARD_H local value = cfg.Default or "" local card, stroke = BaseCard(self, "Textbox_" .. name, height) TitleBlock(card, name, desc, 0, height, false, 0.5) AttachTooltip(self, card, cfg.Tooltip) Hover(card, card, stroke) local holder, holderStroke = PillField(card, 0.4, 100, 170) holder.Position = UDim2.new(1, -14, 0.5, 0) local box = New("TextBox", { Position = UDim2.new(0, 10, 0, 0), Size = UDim2.new(1, -20, 1, 0), BackgroundTransparency = 1, ClearTextOnFocus = cfg.ClearOnFocus == true, Font = Theme.Font.Regular, Text = value, PlaceholderText = cfg.Placeholder or "Type here...", PlaceholderColor3 = Theme.TextMuted, TextColor3 = Theme.Text, TextSize = 12, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = holder, }) box.Focused:Connect(function() Tween(holderStroke, 0.15, { Color = Theme.AccentLight, Transparency = 0 }) Tween(holder, 0.15, { BackgroundColor3 = Theme.SurfaceHover }) end) box.FocusLost:Connect(function(enterPressed) Tween(holderStroke, 0.15, { Color = Theme.Border, Transparency = 0.1 }) Tween(holder, 0.15, { BackgroundColor3 = Theme.Field }) if cfg.OnlyOnEnter and not enterPressed then box.Text = value return end value = box.Text emit(value) end) local object = {} function object:Set(text) value = tostring(text) box.Text = value emit(value) end function object:GetValue() return value end Register(self, cfg, object) return Destroyable(object, card, self, "element", name, desc) end function TabMethods:CreateKeybind(cfg) local name = cfg.Name or "Keybind" local desc = cfg.Description local key = cfg.Default or Enum.KeyCode.E local listening = false local hasDesc = desc ~= nil and desc ~= "" local height = hasDesc and CARD_H_DESC or CARD_H local emit = Emitter(self, cfg) local window = self._window local card, stroke = BaseCard(self, "Keybind_" .. name, height) TitleBlock(card, name, desc, 110, height) AttachTooltip(self, card, cfg.Tooltip) Hover(card, card, stroke) local pill = New("TextButton", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -14, 0.5, 0), Size = UDim2.fromOffset(92, 26), BackgroundColor3 = Theme.Field, AutoButtonColor = false, Text = key.Name, Font = Theme.Font.Bold, TextSize = 11, TextColor3 = Theme.AccentLight, BorderSizePixel = 0, Parent = card, }) Corner(pill, 7) local pillStroke = Stroke(pill, Theme.Border, 1, 0.1) local listenConn window.Maid:Give(function() if listenConn then listenConn:Disconnect() end end) local function stopListening() listening = false if listenConn then listenConn:Disconnect() listenConn = nil end pill.Text = key.Name Tween(pillStroke, 0.15, { Color = Theme.Border, Transparency = 0.1 }) Tween(pill, 0.15, { BackgroundColor3 = Theme.Field }) end pill.MouseButton1Click:Connect(function() if listening then stopListening() return end listening = true pill.Text = "Press a key..." Tween(pillStroke, 0.15, { Color = Theme.AccentLight, Transparency = 0 }) Tween(pill, 0.15, { BackgroundColor3 = Theme.SurfaceHover }) listenConn = UserInputService.InputBegan:Connect(function(input) if input.UserInputType ~= Enum.UserInputType.Keyboard then return end if input.KeyCode ~= Enum.KeyCode.Escape then key = input.KeyCode emit(key) end stopListening() end) end) window.Maid:Give(UserInputService.InputBegan:Connect(function(input, processed) if not processed and not listening and input.KeyCode == key then Fire(cfg.OnPressed) end end)) local object = {} function object:Set(newKey) if typeof(newKey) == "EnumItem" then key = newKey pill.Text = key.Name emit(key) end end function object:GetValue() return key end Register(self, cfg, object) return Destroyable(object, card, self, "element", name, desc) end function TabMethods:CreateColorPicker(cfg) local name = cfg.Name or "Color" local desc = cfg.Description local color = cfg.Default or Theme.Accent local h, s, v = color:ToHSV() local emit = Emitter(self, cfg) local hasDesc = desc ~= nil and desc ~= "" local headerH = hasDesc and CARD_H_DESC or CARD_H local isOpen = false local SV_H = 116 local card, stroke = BaseCard(self, "ColorPicker_" .. name, headerH) card.ClipsDescendants = true TitleBlock(card, name, desc, 140, headerH) AttachTooltip(self, card, cfg.Tooltip) local header = New("TextButton", { Size = UDim2.new(1, 0, 0, headerH), BackgroundTransparency = 1, Text = "", ZIndex = 3, Parent = card, }) Hover(header, card, stroke) local swatch = New("Frame", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -14, 0, headerH / 2), Size = UDim2.fromOffset(34, 22), BackgroundColor3 = color, BorderSizePixel = 0, Parent = card, }) Corner(swatch, 6) Stroke(swatch, WHITE, 1, 0.8) local hexLabel = New("TextLabel", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -56, 0, headerH / 2), Size = UDim2.fromOffset(70, 20), BackgroundTransparency = 1, Text = ToHex(color), Font = Theme.Font.Bold, TextSize = 11, TextColor3 = Theme.TextSecondary, TextXAlignment = Enum.TextXAlignment.Right, Parent = card, }) local body = New("Frame", { Position = UDim2.new(0, 14, 0, headerH + 4), Size = UDim2.new(1, -28, 0, SV_H + 40), BackgroundTransparency = 1, Parent = card, }) local sv = New("Frame", { Size = UDim2.new(1, -26, 0, SV_H), BackgroundColor3 = Color3.fromHSV(h, 1, 1), BorderSizePixel = 0, Parent = body, }) Corner(sv, 7) local whiteLayer = New("Frame", { Size = UDim2.fromScale(1, 1), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = sv, }) Corner(whiteLayer, 7) Gradient( whiteLayer, ColorSequence.new(WHITE), 0, NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(1, 1) }) ) local blackLayer = New("Frame", { Size = UDim2.fromScale(1, 1), BackgroundColor3 = Color3.new(0, 0, 0), BorderSizePixel = 0, Parent = sv, }) Corner(blackLayer, 7) Gradient( blackLayer, ColorSequence.new(Color3.new(0, 0, 0)), 90, NumberSequence.new({ NumberSequenceKeypoint.new(0, 1), NumberSequenceKeypoint.new(1, 0) }) ) local svCursor = New("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Size = UDim2.fromOffset(14, 14), BackgroundTransparency = 1, ZIndex = 3, Parent = sv, }) Corner(svCursor, 7) Stroke(svCursor, WHITE, 2, 0) local svHit = New("TextButton", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Text = "", ZIndex = 4, Parent = sv, }) local hue = New("Frame", { Position = UDim2.new(1, -16, 0, 0), Size = UDim2.fromOffset(16, SV_H), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = body, }) Corner(hue, 8) Gradient( hue, ColorSequence.new({ ColorSequenceKeypoint.new(0, Color3.fromRGB(255, 0, 0)), ColorSequenceKeypoint.new(1 / 6, Color3.fromRGB(255, 255, 0)), ColorSequenceKeypoint.new(2 / 6, Color3.fromRGB(0, 255, 0)), ColorSequenceKeypoint.new(3 / 6, Color3.fromRGB(0, 255, 255)), ColorSequenceKeypoint.new(4 / 6, Color3.fromRGB(0, 0, 255)), ColorSequenceKeypoint.new(5 / 6, Color3.fromRGB(255, 0, 255)), ColorSequenceKeypoint.new(1, Color3.fromRGB(255, 0, 0)), }), 90 ) local hueCursor = New("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Size = UDim2.new(1, 4, 0, 6), BackgroundTransparency = 1, ZIndex = 3, Parent = hue, }) Corner(hueCursor, 3) Stroke(hueCursor, WHITE, 2, 0) local hueHit = New("TextButton", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Text = "", ZIndex = 4, Parent = hue, }) local hexHolder = New("Frame", { Position = UDim2.new(0, 0, 0, SV_H + 10), Size = UDim2.new(1, 0, 0, 26), BackgroundTransparency = 1, Parent = body, }) New("TextLabel", { Size = UDim2.fromOffset(34, 26), BackgroundTransparency = 1, Text = "Hex", Font = Theme.Font.Medium, TextSize = 12, TextColor3 = Theme.TextSecondary, TextXAlignment = Enum.TextXAlignment.Left, Parent = hexHolder, }) local hexField = New("Frame", { Position = UDim2.fromOffset(36, 0), Size = UDim2.fromOffset(100, 26), BackgroundColor3 = Theme.Field, BorderSizePixel = 0, Parent = hexHolder, }) Corner(hexField, 7) local hexStroke = Stroke(hexField, Theme.Border, 1, 0.1) local hexBox = New("TextBox", { Position = UDim2.new(0, 10, 0, 0), Size = UDim2.new(1, -20, 1, 0), BackgroundTransparency = 1, ClearTextOnFocus = false, Font = Theme.Font.Bold, Text = ToHex(color), TextColor3 = Theme.AccentLight, TextSize = 12, TextXAlignment = Enum.TextXAlignment.Left, Parent = hexField, }) local function render(silent) color = Color3.fromHSV(h, s, v) sv.BackgroundColor3 = Color3.fromHSV(h, 1, 1) svCursor.Position = UDim2.fromScale(s, 1 - v) hueCursor.Position = UDim2.fromScale(0.5, h) swatch.BackgroundColor3 = color hexLabel.Text = ToHex(color) if not hexBox:IsFocused() then hexBox.Text = ToHex(color) end if not silent then emit(color) end end render(true) local function dragArea(hit, onPos) hit.InputBegan:Connect(function(input) if not IsPress(input) then return end self._page.ScrollingEnabled = false onPos(input.Position) TrackDrag(input, onPos, function() self._page.ScrollingEnabled = true end) end) end dragArea(svHit, function(pos) local px = math.clamp((pos.X - sv.AbsolutePosition.X) / math.max(sv.AbsoluteSize.X, 1), 0, 1) local py = math.clamp((pos.Y - sv.AbsolutePosition.Y) / math.max(sv.AbsoluteSize.Y, 1), 0, 1) s, v = px, 1 - py render() end) dragArea(hueHit, function(pos) h = math.clamp((pos.Y - hue.AbsolutePosition.Y) / math.max(hue.AbsoluteSize.Y, 1), 0, 0.999) render() end) hexBox.Focused:Connect(function() Tween(hexStroke, 0.15, { Color = Theme.AccentLight, Transparency = 0 }) end) hexBox.FocusLost:Connect(function() Tween(hexStroke, 0.15, { Color = Theme.Border, Transparency = 0.1 }) local parsed = FromHex(hexBox.Text) if parsed then h, s, v = parsed:ToHSV() render() else hexBox.Text = ToHex(color) end end) header.MouseButton1Click:Connect(function() isOpen = not isOpen Tween(card, 0.32, { Size = UDim2.new(1, 0, 0, isOpen and (headerH + SV_H + 52) or headerH) }) end) local object = {} function object:Set(newColor) if typeof(newColor) == "Color3" then h, s, v = newColor:ToHSV() render() end end function object:GetValue() return color end Register(self, cfg, object) return Destroyable(object, card, self, "element", name, desc) end local SIDEBAR_W = 180 local SIDEBAR_COMPACT_W = 132 local HEADER_H = 48 local TAB_H = 36 local TAB_GAP = 4 local SEARCH_Y = 46 local TABS_Y = 84 local FOOTER_H = 62 local COMPACT_BREAKPOINT = 600 local function Contains(text, query) return text ~= nil and text ~= "" and string.find(string.lower(text), query, 1, true) ~= nil end local Tab = setmetatable({}, { __index = TabMethods }) Tab.__index = Tab function Tab.new(window, config, index) local self = setmetatable({}, Tab) self.Name = config.Name or "Tab" self._index = index self._window = window self._order = 0 self._items = {} self._matched = true local iconId = NormalizeIcon(config.Icon) if iconId == "rbxassetid://0" then iconId = nil end self._button = New("TextButton", { Name = self.Name, Size = UDim2.new(1, 0, 0, TAB_H), BackgroundColor3 = Theme.SurfaceHover, BackgroundTransparency = 1, AutoButtonColor = false, Text = "", LayoutOrder = index, Parent = window._tabList, }) Corner(self._button, 9) if iconId then self._icon = New("ImageLabel", { Position = UDim2.new(0, 12, 0.5, -8), Size = UDim2.fromOffset(16, 16), BackgroundTransparency = 1, Image = iconId, ImageColor3 = Theme.TextSecondary, Parent = self._button, }) else self._dot = New("Frame", { Position = UDim2.new(0, 16, 0.5, -3), Size = UDim2.fromOffset(6, 6), BackgroundColor3 = Theme.TextMuted, BorderSizePixel = 0, Parent = self._button, }) Corner(self._dot, 3) end self._label = New("TextLabel", { Position = UDim2.new(0, 38, 0, 0), Size = UDim2.new(1, -46, 1, 0), BackgroundTransparency = 1, Text = self.Name, Font = Theme.Font.Medium, TextSize = 13, TextColor3 = Theme.TextSecondary, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = self._button, }) self._page = New("ScrollingFrame", { Name = self.Name .. "_Page", Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, BorderSizePixel = 0, ScrollBarThickness = 3, ScrollBarImageColor3 = Theme.Accent, ScrollBarImageTransparency = 0.3, CanvasSize = UDim2.new(), AutomaticCanvasSize = Enum.AutomaticSize.Y, ScrollingDirection = Enum.ScrollingDirection.Y, Visible = false, Parent = window._pagesHolder, }) New("UIPadding", { PaddingTop = UDim.new(0, 8), PaddingBottom = UDim.new(0, 18), PaddingLeft = UDim.new(0, 16), PaddingRight = UDim.new(0, 18), Parent = self._page, }) New("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 8), Parent = self._page, }) self._button.MouseButton1Click:Connect(function() window:SelectTab(self) end) self._button.MouseEnter:Connect(function() if window.CurrentTab ~= self then Tween(self._button, 0.15, { BackgroundTransparency = 0.55 }) Tween(self._label, 0.15, { TextColor3 = Theme.Text }) end end) self._button.MouseLeave:Connect(function() if window.CurrentTab ~= self then Tween(self._button, 0.15, { BackgroundTransparency = 1 }) Tween(self._label, 0.15, { TextColor3 = Theme.TextSecondary }) end end) return self end function Tab:_setActive(active, instant) local labelColor = active and WHITE or Theme.TextSecondary local markColor = active and WHITE or Theme.TextMuted self._page.Visible = active if active then Tween(self._button, 0.15, { BackgroundTransparency = 1 }) if not instant then self._page.Position = UDim2.fromOffset(0, 12) Tween(self._page, 0.38, { Position = UDim2.fromOffset(0, 0) }) end end Tween(self._label, 0.2, { TextColor3 = labelColor }) if self._icon then Tween(self._icon, 0.2, { ImageColor3 = active and WHITE or Theme.TextSecondary }) end if self._dot then Tween(self._dot, 0.2, { BackgroundColor3 = markColor }) end end function Tab:ApplySearch(query) if query == "" then for _, item in ipairs(self._items) do item.matched = true item.frame.Visible = not item.hidden end self._matched = true self._button.Visible = true return true end local tabMatch = Contains(self.Name, query) local found = tabMatch local header, headerMatch = nil, false for _, item in ipairs(self._items) do if item.kind == "divider" then item.matched = tabMatch elseif item.kind == "section" then header = item headerMatch = Contains(item.name, query) item.matched = tabMatch or headerMatch if headerMatch then found = true end else local matched = tabMatch or headerMatch or Contains(item.name, query) or Contains(item.desc, query) item.matched = matched if matched then found = true if header and not header.matched then header.matched = true header.frame.Visible = not header.hidden end end end item.frame.Visible = item.matched and not item.hidden end self._matched = found self._button.Visible = found return found end local Window = {} Window.__index = Window function Window.new(config) config = config or {} local self = setmetatable({}, Window) self.Title = config.Title or "Excalibur" self.SubTitle = config.SubTitle or "UI Library" self.Flags = {} self.Elements = {} self.Tabs = {} self.CurrentTab = nil self.Maid = NewMaid() self.Open = true self.Minimized = false self.Maximized = false self.Destroyed = false self.ToggleKey = config.ToggleKey or config.Keybind or Enum.KeyCode.RightShift self.ConfigFolder = config.ConfigFolder or "Excalibur" self._token = 0 self._compact = false self._layoutReady = false self._selectorReady = false local baseSize = config.Size or UDim2.fromOffset(660, 440) if baseSize.X.Offset <= 0 or baseSize.Y.Offset <= 0 then baseSize = UDim2.fromOffset(660, 440) end self._baseMax = Vector2.new(baseSize.X.Offset, baseSize.Y.Offset) self._baseRatio = self._baseMax.X / self._baseMax.Y self:_buildFrame() self:_buildSidebar(config) self:_buildContent() self:_buildTooltip() self:_bindChrome() self:_bindInputs(config) self:_buildFloating(config) Mount(self._gui) self:_applyViewport() self:_applyLayout() self._scale.Scale = 0.9 Tween(self._scale, 0.45, { Scale = 1 }) return self end function Window:_buildFrame() self._gui = New("ScreenGui", { Name = "Excalibur_" .. self.Title:gsub("%s+", "_"), ResetOnSpawn = false, DisplayOrder = 500, ZIndexBehavior = Enum.ZIndexBehavior.Sibling, }) self._root = New("Frame", { Name = "Root", AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.fromScale(0.94, 0.92), BackgroundTransparency = 1, Parent = self._gui, }) self._aspect = New("UIAspectRatioConstraint", { AspectRatio = self._baseRatio, AspectType = Enum.AspectType.FitWithinMaxSize, DominantAxis = Enum.DominantAxis.Width, Parent = self._root, }) self._sizeConstraint = New("UISizeConstraint", { MinSize = Vector2.new(330, 230), MaxSize = self._baseMax, Parent = self._root, }) self._scale = New("UIScale", { Scale = 1, Parent = self._root }) self._shell = New("Frame", { Name = "Shell", Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Parent = self._root, }) local _, main = BuildChrome(self._shell) self._main = main end function Window:_buildSidebar(config) local sidebarSeq = ColorSequence.new(Theme.SidebarTop, Theme.SidebarBottom) self._sidebar = New("Frame", { Name = "Sidebar", Size = UDim2.new(0, SIDEBAR_W, 1, 0), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = self._main, }) Corner(self._sidebar, 12) Gradient(self._sidebar, sidebarSeq, 90) local cover = New("Frame", { Position = UDim2.new(1, -14, 0, 0), Size = UDim2.new(0, 14, 1, 0), BackgroundColor3 = WHITE, BorderSizePixel = 0, Parent = self._sidebar, }) Gradient(cover, sidebarSeq, 90) New("Frame", { Position = UDim2.new(1, -1, 0, 0), Size = UDim2.new(0, 1, 1, 0), BackgroundColor3 = Theme.Border, BackgroundTransparency = 0.35, BorderSizePixel = 0, Parent = self._sidebar, }) self._sidebarHeader = New("Frame", { Name = "Header", Size = UDim2.new(1, 0, 0, HEADER_H), BackgroundTransparency = 1, Parent = self._sidebar, }) local _, close, minimize, maximize = TrafficLights(self._sidebarHeader, true) self._closeDot, self._minimizeDot, self._maximizeDot = close, minimize, maximize local body = New("Frame", { Name = "Body", Position = UDim2.new(0, 0, 0, HEADER_H), Size = UDim2.new(1, 0, 1, -HEADER_H), BackgroundTransparency = 1, Parent = self._sidebar, }) self._sidebarBody = body self._logo = Logo.new(body, 34, 9, self.Title, config.Icon) self._logo.Frame.Position = UDim2.new(0, 16, 0, 2) New("TextLabel", { Position = UDim2.new(0, 58, 0, 3), Size = UDim2.new(1, -66, 0, 18), BackgroundTransparency = 1, Text = self.Title, Font = Theme.Font.Bold, TextSize = 14, TextColor3 = Theme.Text, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = body, }) self._brandSubtitle = New("TextLabel", { Position = UDim2.new(0, 58, 0, 21), Size = UDim2.new(1, -66, 0, 15), BackgroundTransparency = 1, Text = self.SubTitle, Font = Theme.Font.Regular, TextSize = 11, TextColor3 = Theme.TextMuted, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = body, }) local field = New("Frame", { Name = "Search", Position = UDim2.new(0, 10, 0, SEARCH_Y), Size = UDim2.new(1, -20, 0, 30), BackgroundColor3 = Theme.Field, BorderSizePixel = 0, Parent = body, }) Corner(field, 8) local fieldStroke = Stroke(field, Theme.Border, 1, 0.1) local lens = New("Frame", { Position = UDim2.fromOffset(10, 8), Size = UDim2.fromOffset(14, 14), BackgroundTransparency = 1, Parent = field, }) local ring = New("Frame", { Size = UDim2.fromOffset(9, 9), BackgroundTransparency = 1, BorderSizePixel = 0, Parent = lens, }) Corner(ring, 5) New("UIStroke", { Color = Theme.TextMuted, Thickness = 1.5, Parent = ring }) Bar(lens, 0.4, 0.14, 45, Theme.TextMuted, 0.78, 0.82) self._searchBox = New("TextBox", { Position = UDim2.new(0, 30, 0, 0), Size = UDim2.new(1, -54, 1, 0), BackgroundTransparency = 1, ClearTextOnFocus = false, Font = Theme.Font.Regular, Text = "", PlaceholderText = "Search...", PlaceholderColor3 = Theme.TextMuted, TextColor3 = Theme.Text, TextSize = 12, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = field, }) self._searchClear = New("TextButton", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -6, 0.5, 0), Size = UDim2.fromOffset(18, 18), BackgroundTransparency = 1, Text = "", Visible = false, Parent = field, }) Bar(self._searchClear, 0.6, 0.1, 45, Theme.TextMuted) Bar(self._searchClear, 0.6, 0.1, -45, Theme.TextMuted) self._searchStroke = fieldStroke self._tabScroll = New("ScrollingFrame", { Name = "Tabs", Position = UDim2.new(0, 10, 0, TABS_Y), Size = UDim2.new(1, -20, 1, -(TABS_Y + FOOTER_H)), BackgroundTransparency = 1, BorderSizePixel = 0, ScrollBarThickness = 0, CanvasSize = UDim2.new(), AutomaticCanvasSize = Enum.AutomaticSize.Y, Parent = body, }) self._selector = New("Frame", { Name = "Selector", Size = UDim2.new(1, 0, 0, TAB_H), BackgroundColor3 = WHITE, BorderSizePixel = 0, Visible = false, ZIndex = 1, Parent = self._tabScroll, }) Corner(self._selector, 9) Gradient(self._selector, ColorSequence.new(Theme.Accent, Theme.AccentMid), 0) Stroke(self._selector, Theme.AccentEnd, 1, 0.55) self._tabList = New("Frame", { Name = "List", Size = UDim2.new(1, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundTransparency = 1, ZIndex = 2, Parent = self._tabScroll, }) New("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, TAB_GAP), Parent = self._tabList, }) self._emptyLabel = New("TextLabel", { Position = UDim2.new(0, 10, 0, TABS_Y + 8), Size = UDim2.new(1, -20, 0, 20), BackgroundTransparency = 1, Text = "No results", Font = Theme.Font.Medium, TextSize = 12, TextColor3 = Theme.TextMuted, Visible = false, Parent = body, }) local player = Players.LocalPlayer if player then local footer = New("Frame", { Name = "Footer", Position = UDim2.new(0, 10, 1, -54), Size = UDim2.new(1, -20, 0, 46), BackgroundColor3 = Theme.Surface, BackgroundTransparency = 0.3, BorderSizePixel = 0, Parent = body, }) Corner(footer, 10) Stroke(footer, Theme.Border, 1, 0.4) local avatar = New("ImageLabel", { Position = UDim2.new(0, 9, 0.5, -15), Size = UDim2.fromOffset(30, 30), BackgroundColor3 = Theme.Field, Image = "", Parent = footer, }) Corner(avatar, 15) Stroke(avatar, Theme.AccentLight, 1.5, 0.3) local online = New("Frame", { Position = UDim2.new(0, 31, 0.5, 6), Size = UDim2.fromOffset(9, 9), BackgroundColor3 = Theme.Success, BorderSizePixel = 0, ZIndex = 3, Parent = footer, }) Corner(online, 5) Stroke(online, Theme.Surface, 2, 0) New("TextLabel", { Position = UDim2.new(0, 48, 0, 7), Size = UDim2.new(1, -54, 0, 16), BackgroundTransparency = 1, Text = player.DisplayName, Font = Theme.Font.Bold, TextSize = 12, TextColor3 = Theme.Text, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = footer, }) New("TextLabel", { Position = UDim2.new(0, 48, 0, 23), Size = UDim2.new(1, -54, 0, 14), BackgroundTransparency = 1, Text = "@" .. player.Name, Font = Theme.Font.Regular, TextSize = 10, TextColor3 = Theme.TextMuted, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = footer, }) self._footer = footer task.spawn(function() local ok, image = pcall(function() return Players:GetUserThumbnailAsync( player.UserId, Enum.ThumbnailType.HeadShot, Enum.ThumbnailSize.Size48x48 ) end) if ok and avatar.Parent then avatar.Image = image end end) end end function Window:_buildContent() self._content = New("Frame", { Name = "Content", Position = UDim2.new(0, SIDEBAR_W, 0, 0), Size = UDim2.new(1, -SIDEBAR_W, 1, 0), BackgroundTransparency = 1, Parent = self._main, }) self._header = New("Frame", { Name = "Header", Size = UDim2.new(1, 0, 0, HEADER_H), BackgroundTransparency = 1, Parent = self._content, }) self._pageTitle = New("TextLabel", { Position = UDim2.new(0, 20, 0, 0), Size = UDim2.new(1, -170, 1, 0), BackgroundTransparency = 1, Text = "", Font = Theme.Font.Bold, TextSize = 17, TextColor3 = Theme.Text, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = self._header, }) self._keyPill = New("Frame", { AnchorPoint = Vector2.new(1, 0.5), Position = UDim2.new(1, -16, 0.5, 0), Size = UDim2.fromOffset(96, 24), BackgroundColor3 = Theme.Field, BorderSizePixel = 0, Parent = self._header, }) Corner(self._keyPill, 7) Stroke(self._keyPill, Theme.Border, 1, 0.2) self._keyLabel = New("TextLabel", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Text = self.ToggleKey.Name, Font = Theme.Font.Bold, TextSize = 10, TextColor3 = Theme.TextSecondary, Parent = self._keyPill, }) New("Frame", { Position = UDim2.new(0, 16, 1, -1), Size = UDim2.new(1, -32, 0, 1), BackgroundColor3 = Theme.Border, BackgroundTransparency = 0.45, BorderSizePixel = 0, Parent = self._header, }) self._pagesHolder = New("Frame", { Name = "Pages", Position = UDim2.new(0, 0, 0, HEADER_H + 1), Size = UDim2.new(1, 0, 1, -(HEADER_H + 1)), BackgroundTransparency = 1, ClipsDescendants = true, Parent = self._content, }) MakeDraggable(self._sidebarHeader, self._root) MakeDraggable(self._header, self._root) end function Window:_buildFloating(config) local mode = config.FloatingButton local show if mode == nil or mode == "auto" then show = UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled else show = mode == true end if not show then return end local orb = New("Frame", { Name = "FloatingToggle", Position = UDim2.new(0, 14, 0.5, -23), Size = UDim2.fromOffset(46, 46), BackgroundTransparency = 1, Parent = self._gui, }) self._orbLogo = Logo.new(orb, 46, 23, self.Title, config.Icon) local hit = New("TextButton", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Text = "", ZIndex = 5, Parent = orb, }) hit.InputBegan:Connect(function(input) if not IsPress(input) then return end local startPos = input.Position local origin = orb.Position local moved = false TrackDrag(input, function(pos) local delta = pos - startPos if delta.Magnitude > 8 then moved = true end if moved then orb.Position = UDim2.new(origin.X.Scale, origin.X.Offset + delta.X, origin.Y.Scale, origin.Y.Offset + delta.Y) end end, function() if not moved then self:Toggle() end end) end) self._orb = orb end function Window:_bindChrome() self._closeDot.MouseButton1Click:Connect(function() self:Toggle(false) local hint = UserInputService.KeyboardEnabled and ("Press " .. self.ToggleKey.Name .. " to reopen.") or "Tap the floating button to reopen." self:Notify({ Content = "Window hidden. " .. hint, Duration = 3 }) end) self._minimizeDot.MouseButton1Click:Connect(function() self:Minimize() end) self._maximizeDot.MouseButton1Click:Connect(function() self:Maximize() end) local box = self._searchBox box.Focused:Connect(function() Tween(self._searchStroke, 0.15, { Color = Theme.AccentLight, Transparency = 0 }) end) box.FocusLost:Connect(function() Tween(self._searchStroke, 0.15, { Color = Theme.Border, Transparency = 0.1 }) end) box:GetPropertyChangedSignal("Text"):Connect(function() self._searchClear.Visible = box.Text ~= "" self:_applySearch(box.Text) end) self._searchClear.MouseButton1Click:Connect(function() box.Text = "" end) end function Window:_bindInputs(config) self.Maid:Give(UserInputService.InputBegan:Connect(function(input, processed) if not processed and input.KeyCode == self.ToggleKey then self:Toggle() end end)) self.Maid:Give(self._root:GetPropertyChangedSignal("AbsoluteSize"):Connect(function() self:_applyLayout() end)) local camera = workspace.CurrentCamera if camera then self.Maid:Give(camera:GetPropertyChangedSignal("ViewportSize"):Connect(function() self:_applyViewport() end)) end if config.MobileGesture then self.Maid:Give(UserInputService.TouchSwipe:Connect(function(_, touches, processed) if not processed and touches >= 3 then self:Toggle() end end)) end self.Maid:Give(StopAllDrags) end function Window:_targets() if self.Maximized then return 1100 / 760, Vector2.new(1100, 760) end local camera = workspace.CurrentCamera local portrait = camera and camera.ViewportSize.X < camera.ViewportSize.Y return portrait and 0.9 or self._baseRatio, self._baseMax end function Window:_applyViewport() local ratio, maxSize = self:_targets() self._aspect.AspectRatio = ratio self._sizeConstraint.MaxSize = maxSize end function Window:_applyLayout() local compact = self._root.AbsoluteSize.X < COMPACT_BREAKPOINT if self._layoutReady and compact == self._compact then return end self._layoutReady = true self._compact = compact local width = compact and SIDEBAR_COMPACT_W or SIDEBAR_W self._sidebar.Size = UDim2.new(0, width, 1, 0) self._content.Position = UDim2.new(0, width, 0, 0) self._content.Size = UDim2.new(1, -width, 1, 0) self._brandSubtitle.Visible = not compact if self._footer then self._footer.Visible = not compact end self._tabScroll.Size = UDim2.new(1, -20, 1, -(TABS_Y + (compact and 8 or FOOTER_H))) local showKey = not compact and UserInputService.KeyboardEnabled self._keyPill.Visible = showKey self._pageTitle.Size = UDim2.new(1, showKey and -170 or -40, 1, 0) end function Window:_positionSelector(animate) local current = self.CurrentTab if not current then return end local slot = 0 for _, tab in ipairs(self.Tabs) do if tab == current then break end if tab._matched then slot = slot + 1 end end local target = UDim2.new(0, 0, 0, slot * (TAB_H + TAB_GAP)) self._selector.Visible = current._matched if animate and self._selectorReady then Tween(self._selector, 0.34, { Position = target }) else self._selector.Position = target self._selectorReady = true end end function Window:_applySearch(text) local query = string.lower(Trim(text)) local first, any = nil, false for _, tab in ipairs(self.Tabs) do local found = tab:ApplySearch(query) if found then any = true first = first or tab end end self._emptyLabel.Visible = query ~= "" and not any if first and (self.CurrentTab == nil or not self.CurrentTab._matched) then self:SelectTab(first) else self:_positionSelector(true) end end function Window:Search(query) query = tostring(query or "") if self._searchBox.Text ~= query then self._searchBox.Text = query else self:_applySearch(query) end end function Window:ClearSearch() self:Search("") end function Window:SelectTab(target) if type(target) == "string" or type(target) == "number" then for index, tab in ipairs(self.Tabs) do if tab.Name == target or index == target then target = tab break end end end if type(target) ~= "table" or self.CurrentTab == target then return end local previous = self.CurrentTab self.CurrentTab = target if previous then previous:_setActive(false) end target:_setActive(true, previous == nil) self._pageTitle.Text = target.Name self:_positionSelector(previous ~= nil) end function Window:CreateTab(config) if type(config) == "string" then config = { Name = config } end local tab = Tab.new(self, config or {}, #self.Tabs + 1) table.insert(self.Tabs, tab) if #self.Tabs == 1 then task.defer(function() if not self.Destroyed then self:SelectTab(tab) end end) end return tab end function Window:_buildTooltip() self._tipToken = 0 self._tipOwner = nil self._tip = New("Frame", { Name = "Tooltip", BackgroundColor3 = WHITE, BackgroundTransparency = 1, BorderSizePixel = 0, Visible = false, ZIndex = 50, Size = UDim2.fromOffset(100, 30), Parent = self._gui, }) Corner(self._tip, 8) Gradient(self._tip, ColorSequence.new(Color3.fromRGB(38, 33, 62), Color3.fromRGB(24, 20, 42)), 90) self._tipStroke = Stroke(self._tip, Theme.BorderHover, 1, 1) self._tipLabel = New("TextLabel", { Position = UDim2.fromOffset(10, 8), Size = UDim2.new(1, -20, 1, -16), BackgroundTransparency = 1, Text = "", Font = Theme.Font.Regular, TextSize = 12, TextColor3 = Theme.Text, TextTransparency = 1, TextWrapped = true, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, ZIndex = 51, Parent = self._tip, }) end function Window:ShowTooltip(anchor, text) if self.Destroyed or not anchor.Parent then return end self._tipToken = self._tipToken + 1 self._tipOwner = anchor local camera = workspace.CurrentCamera local viewport = camera and camera.ViewportSize or Vector2.new(1280, 720) local maxWidth = math.min(240, viewport.X - 24) local bounds = TextService:GetTextSize(text, 12, Theme.Font.Regular, Vector2.new(maxWidth - 20, 1000)) local width = math.max(bounds.X + 22, 60) local height = bounds.Y + 18 local center = anchor.AbsolutePosition + anchor.AbsoluteSize / 2 local x = math.clamp(center.X - width / 2, 8, math.max(viewport.X - width - 8, 8)) local y = center.Y + anchor.AbsoluteSize.Y / 2 + 8 if y + height > viewport.Y - 8 then y = center.Y - anchor.AbsoluteSize.Y / 2 - 8 - height end self._tip.Size = UDim2.fromOffset(width, height) self._tip.Position = UDim2.fromOffset(x, y) self._tipLabel.Text = text self._tip.Visible = true Tween(self._tip, 0.18, { BackgroundTransparency = 0 }) Tween(self._tipStroke, 0.18, { Transparency = 0.1 }) Tween(self._tipLabel, 0.18, { TextTransparency = 0 }) local token = self._tipToken if not UserInputService.MouseEnabled then task.delay(4, function() if not self.Destroyed and token == self._tipToken then self:HideTooltip() end end) end end function Window:HideTooltip(anchor) if self.Destroyed or not self._tip then return end if anchor and self._tipOwner ~= anchor then return end self._tipToken = self._tipToken + 1 self._tipOwner = nil local token = self._tipToken Tween(self._tip, 0.14, { BackgroundTransparency = 1 }) Tween(self._tipStroke, 0.14, { Transparency = 1 }) Tween(self._tipLabel, 0.14, { TextTransparency = 1 }).Completed:Connect(function() if not self.Destroyed and token == self._tipToken then self._tip.Visible = false end end) end function Window:ToggleTooltip(anchor, text) if self._tipOwner == anchor and self._tip.Visible then self:HideTooltip() else self:ShowTooltip(anchor, text) end end function Window:Toggle(state) if state == nil then state = not self.Open end if state == self.Open then return end self.Open = state self:HideTooltip() self._token = self._token + 1 local token = self._token if state then self._root.Visible = true self._scale.Scale = 0.93 Tween(self._scale, 0.34, { Scale = 1 }) else local out = Tween(self._scale, 0.2, { Scale = 0.93 }, Enum.EasingStyle.Quad, Enum.EasingDirection.In) out.Completed:Connect(function() if not self.Open and token == self._token and not self.Destroyed then self._root.Visible = false end end) end end function Window:Minimize(state) if state == nil then state = not self.Minimized end if state == self.Minimized then return end self.Minimized = state if state then self._sidebarBody.Visible = false self._pagesHolder.Visible = false Tween(self._shell, 0.35, { Size = UDim2.new(1, 0, 0, HEADER_H) }) else Tween(self._shell, 0.35, { Size = UDim2.fromScale(1, 1) }) task.delay(0.28, function() if not self.Destroyed and not self.Minimized then self._sidebarBody.Visible = true self._pagesHolder.Visible = true end end) end end function Window:Maximize(state) if state == nil then state = not self.Maximized end if self.Minimized then self:Minimize(false) end self.Maximized = state local ratio, maxSize = self:_targets() Tween(self._aspect, 0.4, { AspectRatio = ratio }) Tween(self._sizeConstraint, 0.4, { MaxSize = maxSize }) Tween(self._root, 0.4, { Position = UDim2.fromScale(0.5, 0.5) }) end function Window:SetToggleKey(key) self.ToggleKey = key self._keyLabel.Text = key.Name end function Window:SetIcon(icon) self._logo:SetIcon(icon) if self._orbLogo then self._orbLogo:SetIcon(icon) end end function Window:Notify(config) if type(config) == "string" then config = { Content = config } end config.Title = config.Title or self.Title return Excalibur:Notify(config) end function Window:_configPath(name) return self.ConfigFolder .. "/" .. (name or "default") .. ".json" end function Window:SaveConfig(name) local data = {} for flag, value in pairs(self.Flags) do data[flag] = EncodeValue(value) end local ok, encoded = pcall(function() return HttpService:JSONEncode(data) end) if not ok then return false end return WriteFile(self:_configPath(name), encoded) end function Window:LoadConfig(name) local content = ReadFile(self:_configPath(name)) if not content then return false end local ok, data = pcall(function() return HttpService:JSONDecode(content) end) if not ok or type(data) ~= "table" then return false end for flag, raw in pairs(data) do local element = self.Elements[flag] local value = DecodeValue(raw) if element and value ~= nil then pcall(function() element:Set(value) end) end end return true end function Window:ListConfigs() local env = Env() local names = {} if env.listfiles and env.isfolder and env.isfolder(self.ConfigFolder) then for _, file in ipairs(env.listfiles(self.ConfigFolder)) do local base = file:match("([^/\\]+)%.json$") if base then table.insert(names, base) end end end return names end function Window:OnUnload(callback) self.Maid:Give(callback) return self end function Window:Destroy() if self.Destroyed then return end self.Destroyed = true self.Maid:Clean() self._gui:Destroy() local index = table.find(Excalibur.Windows, self) if index then table.remove(Excalibur.Windows, index) end table.clear(self.Elements) table.clear(self.Flags) table.clear(self.Tabs) self.CurrentTab = nil end Window.Unload = Window.Destroy local function ActionButton(parent, text, primary, position, size) local holder = New("Frame", { Position = position, Size = size, BackgroundTransparency = 1, Parent = parent, }) local fill = New("Frame", { Size = UDim2.fromScale(1, 1), BackgroundColor3 = primary and WHITE or Theme.Surface, BorderSizePixel = 0, Parent = holder, }) Corner(fill, 10) local stroke = Stroke(fill, primary and Theme.AccentLight or Theme.Border, 1, primary and 0.5 or 0.2) if primary then Gradient(fill, ColorSequence.new(Theme.Accent, Theme.AccentEnd), 0) else Gradient(fill, ColorSequence.new(WHITE, Color3.fromRGB(212, 205, 236)), 90) end local button = New("TextButton", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, AutoButtonColor = false, Text = text, Font = Theme.Font.Bold, TextSize = 13, TextColor3 = primary and WHITE or Theme.Text, ZIndex = 2, Parent = holder, }) local scale = New("UIScale", { Parent = holder }) button.MouseEnter:Connect(function() if primary then Tween(stroke, 0.18, { Transparency = 0 }) else Tween(fill, 0.18, { BackgroundColor3 = Theme.SurfaceHover }) Tween(stroke, 0.18, { Color = Theme.BorderHover, Transparency = 0 }) end end) button.MouseLeave:Connect(function() if primary then Tween(stroke, 0.18, { Transparency = 0.5 }) else Tween(fill, 0.18, { BackgroundColor3 = Theme.Surface }) Tween(stroke, 0.18, { Color = Theme.Border, Transparency = 0.2 }) end Tween(scale, 0.15, { Scale = 1 }) end) button.MouseButton1Down:Connect(function() Tween(scale, 0.1, { Scale = 0.97 }, Enum.EasingStyle.Quad) end) button.MouseButton1Up:Connect(function() Tween(scale, 0.2, { Scale = 1 }) end) return button, fill end local KeySystem = {} KeySystem.__index = KeySystem local KEY_WIDTH = 380 local KEY_HEIGHT = 346 local KEY_DISCORD_EXTRA = 48 local function ResolveInvite(invite) if type(invite) ~= "string" then return nil end invite = Trim(invite) if invite == "" then return nil end return invite end function KeySystem.new(config) config = config or {} if type(config.Validate) ~= "function" and not config.Keys and not config.Key then error("[Excalibur] KeySystem requires either Keys or Validate", 2) end local self = setmetatable({}, KeySystem) self.Config = config self.Title = config.Title or "Key Verification" self.FileName = config.FileName or "Excalibur/key.txt" self.SaveKey = config.SaveKey ~= false self.MaxAttempts = config.MaxAttempts self.Timeout = config.Timeout or 15 self.DiscordInvite = ResolveInvite(config.DiscordInvite) self._userScale = math.clamp(tonumber(config.Scale) or 1, 0.6, 1.6) self._height = KEY_HEIGHT + (self.DiscordInvite and KEY_DISCORD_EXTRA or 0) self.Maid = NewMaid() self._attempts = 0 self._busy = false self._finished = false self._destroyed = false self._remember = self.SaveKey self._baseScale = 1 self._event = Instance.new("BindableEvent") table.insert(Excalibur.KeySystems, self) return self end function KeySystem:_validate(key) local config = self.Config key = Trim(key) if key == "" then return false, "Enter your key first" end if type(config.Validate) == "function" then local called, result, message = pcall(config.Validate, key) if not called then return false, "Validation failed. Try again later" end if result == true then return true end return false, type(message) == "string" and message or "Invalid key" end local keys = config.Keys or config.Key if type(keys) == "string" then if keys == key then return true end return false, "Invalid key" end if type(keys) == "table" then if keys[key] == true then return true end for _, candidate in ipairs(keys) do if candidate == key then return true end end end return false, "Invalid key" end function KeySystem:_readSaved() local content = ReadFile(self.FileName) if content and Trim(content) ~= "" then return Trim(content) end return nil end function KeySystem:ClearSaved() if not DeleteFile(self.FileName) then WriteFile(self.FileName, "") end end function KeySystem:_fit() local camera = workspace.CurrentCamera if not camera then return end local viewport = camera.ViewportSize local fit = math.min(viewport.X * 0.92 / KEY_WIDTH, viewport.Y * 0.92 / self._height) self._baseScale = math.clamp(math.min(fit, self._userScale), 0.5, 1.6) if not self._finished then self._scale.Scale = self._baseScale end end function KeySystem:_setStatus(text, color) self._status.Text = text self._status.TextColor3 = color or Theme.TextMuted end function KeySystem:_setBusy(state) self._verify.Text = state and "Verifying..." or "Verify Key" self._verify.AutoButtonColor = false Tween(self._verifyFill, 0.15, { BackgroundTransparency = state and 0.45 or 0 }) end function KeySystem:_shake() local origin = self._root.Position Tween(self._inputStroke, 0.15, { Color = Theme.Error, Transparency = 0 }) task.delay(0.9, function() if not self._destroyed then Tween(self._inputStroke, 0.25, { Color = Theme.Border, Transparency = 0.1 }) end end) task.spawn(function() for _, offset in ipairs({ -10, 10, -6, 6, 0 }) do if self._destroyed then return end Tween( self._root, 0.05, { Position = UDim2.new(origin.X.Scale, origin.X.Offset + offset, origin.Y.Scale, origin.Y.Offset) }, Enum.EasingStyle.Quad ) task.wait(0.05) end end) end function KeySystem:_finish(ok, key) if self._finished then return end self._finished = true Tween(self._scale, 0.25, { Scale = self._baseScale * 0.92 }, Enum.EasingStyle.Quad, Enum.EasingDirection.In) Tween(self._backdrop, 0.25, { BackgroundTransparency = 1 }) task.delay(0.26, function() if not self._destroyed then self._event:Fire(ok, key) end end) end function KeySystem:_submit() if self._busy or self._finished then return end local key = Trim(self._box.Text) self._busy = true self:_setBusy(true) local settled = false local function settle(ok, message) if settled or self._destroyed then return end settled = true self._busy = false self:_setBusy(false) if ok then if self.SaveKey and self._remember then WriteFile(self.FileName, key) end self:_setStatus("Key accepted", Theme.Success) Excalibur:Notify({ Title = self.Title, Content = "Key accepted. Loading...", Type = "Success" }) self:_finish(true, key) return end self._attempts = self._attempts + 1 self:_setStatus(message or "Invalid key", Theme.Error) self:_shake() Excalibur:Notify({ Title = self.Title, Content = message or "Invalid key", Type = "Error" }) if self.MaxAttempts and self._attempts >= self.MaxAttempts then Excalibur:Notify({ Title = self.Title, Content = "Too many failed attempts.", Type = "Warning" }) self:_finish(false) end end task.spawn(function() local ok, message = self:_validate(key) settle(ok, message) end) task.delay(self.Timeout, function() settle(false, "Validation timed out") end) end function KeySystem:_copy(text, message) local setClipboard = Env().setclipboard if type(setClipboard) == "function" and pcall(setClipboard, text) then Excalibur:Notify({ Title = self.Title, Content = message, Type = "Info" }) return end Excalibur:Notify({ Title = self.Title, Content = text, Type = "Info", Duration = 8 }) end function KeySystem:_buildActions(main) local link = self.Config.GetKeyLink if link then local getKey = ActionButton(main, "Get Key", false, UDim2.new(0, 24, 0, 286), UDim2.new(0.5, -30, 0, 40)) self._verify, self._verifyFill = ActionButton(main, "Verify Key", true, UDim2.new(0.5, 6, 0, 286), UDim2.new(0.5, -30, 0, 40)) getKey.MouseButton1Click:Connect(function() self:_copy(link, "Link copied to clipboard.") end) else self._verify, self._verifyFill = ActionButton(main, "Verify Key", true, UDim2.new(0, 24, 0, 286), UDim2.new(1, -48, 0, 40)) end self._verify.MouseButton1Click:Connect(function() self:_submit() end) if self.DiscordInvite then local discord = ActionButton(main, "Copy Discord Invite", false, UDim2.new(0, 24, 0, 334), UDim2.new(1, -48, 0, 40)) discord.MouseButton1Click:Connect(function() self:_copy(self.DiscordInvite, "Discord invite copied to clipboard.") end) end end function KeySystem:_build() local config = self.Config self._gui = New("ScreenGui", { Name = "Excalibur_KeySystem", DisplayOrder = 900, ResetOnSpawn = false, IgnoreGuiInset = true, ZIndexBehavior = Enum.ZIndexBehavior.Sibling, }) self._backdrop = New("TextButton", { Name = "Backdrop", Size = UDim2.fromScale(1, 1), BackgroundColor3 = Color3.fromRGB(6, 4, 16), BackgroundTransparency = 1, AutoButtonColor = false, Modal = true, Text = "", BorderSizePixel = 0, Parent = self._gui, }) Tween(self._backdrop, 0.4, { BackgroundTransparency = 0.4 }) self._root = New("Frame", { Name = "Root", AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.fromOffset(KEY_WIDTH, self._height), BackgroundTransparency = 1, Parent = self._gui, }) self._scale = New("UIScale", { Scale = 1, Parent = self._root }) local _, main = BuildChrome(self._root) local header = New("Frame", { Size = UDim2.new(1, 0, 0, HEADER_H), BackgroundTransparency = 1, Parent = main, }) local _, close = TrafficLights(header, false) New("TextLabel", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, Text = "Verification", Font = Theme.Font.Medium, TextSize = 12, TextColor3 = Theme.TextMuted, Parent = header, }) MakeDraggable(header, self._root) self._logo = Logo.new(main, 52, 14, config.Title or "Key", config.Icon) self._logo.Frame.Position = UDim2.new(0.5, -26, 0, 58) New("TextLabel", { Position = UDim2.new(0, 24, 0, 118), Size = UDim2.new(1, -48, 0, 24), BackgroundTransparency = 1, Text = self.Title, Font = Theme.Font.Bold, TextSize = 18, TextColor3 = Theme.Text, Parent = main, }) New("TextLabel", { Position = UDim2.new(0, 32, 0, 144), Size = UDim2.new(1, -64, 0, 32), BackgroundTransparency = 1, Text = config.Note or "Enter your key to continue.", Font = Theme.Font.Regular, TextSize = 12, TextColor3 = Theme.TextSecondary, TextWrapped = true, TextYAlignment = Enum.TextYAlignment.Top, Parent = main, }) local field = New("Frame", { Position = UDim2.new(0, 24, 0, 186), Size = UDim2.new(1, -48, 0, 40), BackgroundColor3 = Theme.Field, BorderSizePixel = 0, Parent = main, }) Corner(field, 10) self._inputStroke = Stroke(field, Theme.Border, 1, 0.1) self._box = New("TextBox", { Position = UDim2.new(0, 14, 0, 0), Size = UDim2.new(1, -28, 1, 0), BackgroundTransparency = 1, ClearTextOnFocus = false, Font = Theme.Font.Medium, Text = "", PlaceholderText = config.Placeholder or "Paste your key here", PlaceholderColor3 = Theme.TextMuted, TextColor3 = Theme.Text, TextSize = 13, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, Parent = field, }) self._box.Focused:Connect(function() Tween(self._inputStroke, 0.15, { Color = Theme.AccentLight, Transparency = 0 }) end) self._box.FocusLost:Connect(function(enterPressed) Tween(self._inputStroke, 0.15, { Color = Theme.Border, Transparency = 0.1 }) if enterPressed then self:_submit() end end) self._status = New("TextLabel", { Position = UDim2.new(0, 24, 0, 230), Size = UDim2.new(1, -48, 0, 16), BackgroundTransparency = 1, Text = "", Font = Theme.Font.Medium, TextSize = 11, TextColor3 = Theme.TextMuted, TextXAlignment = Enum.TextXAlignment.Left, Parent = main, }) if self.SaveKey then local rememberSwitch = Switch(main, 36, 20, self._remember) rememberSwitch.Frame.Position = UDim2.new(0, 60, 0, 262) New("TextLabel", { Position = UDim2.new(0, 68, 0, 252), Size = UDim2.new(1, -92, 0, 20), BackgroundTransparency = 1, Text = "Remember key", Font = Theme.Font.Medium, TextSize = 12, TextColor3 = Theme.TextSecondary, TextXAlignment = Enum.TextXAlignment.Left, Parent = main, }) local rememberHit = New("TextButton", { Position = UDim2.new(0, 24, 0, 250), Size = UDim2.new(1, -48, 0, 24), BackgroundTransparency = 1, Text = "", ZIndex = 5, Parent = main, }) rememberHit.MouseButton1Click:Connect(function() self._remember = not self._remember rememberSwitch:Set(self._remember, true) end) end self:_buildActions(main) close.MouseButton1Click:Connect(function() if self._finished then return end Excalibur:Notify({ Title = self.Title, Content = "Verification cancelled.", Type = "Warning" }) self:_finish(false) end) Mount(self._gui) self:_fit() local camera = workspace.CurrentCamera if camera then self.Maid:Give(camera:GetPropertyChangedSignal("ViewportSize"):Connect(function() self:_fit() end)) end self.Maid:Give(StopAllDrags) self._scale.Scale = self._baseScale * 0.92 Tween(self._scale, 0.4, { Scale = self._baseScale }) end function KeySystem:Run() local saved = self.SaveKey and self:_readSaved() if saved then local ok = self:_validate(saved) if ok then Excalibur:Notify({ Title = self.Title, Content = "Saved key accepted.", Type = "Success" }) self:Destroy() return true, saved end self:ClearSaved() end self:_build() local ok, key = self._event.Event:Wait() self:Destroy() return ok == true, key end function KeySystem:Destroy() if self._destroyed then return end self._destroyed = true self.Maid:Clean() if self._gui then self._gui:Destroy() end self._event:Fire(false) self._event:Destroy() local index = table.find(Excalibur.KeySystems, self) if index then table.remove(Excalibur.KeySystems, index) end end KeySystem.Unload = KeySystem.Destroy function Excalibur:CreateWindow(config) if not (config and config.Multiple) then for index = #self.Windows, 1, -1 do self.Windows[index]:Destroy() end end local window = Window.new(config) table.insert(self.Windows, window) return window end function Excalibur:CreateKeySystem(config) return KeySystem.new(config) end function Excalibur:RequireKey(config) return KeySystem.new(config):Run() end function Excalibur:Unload() for index = #self.Windows, 1, -1 do self.Windows[index]:Destroy() end for index = #self.KeySystems, 1, -1 do self.KeySystems[index]:Destroy() end StopAllDrags() if sharedNotifier then sharedNotifier:Destroy() sharedNotifier = nil end end Excalibur.Destroy = Excalibur.Unload local function PurgeStaleInterfaces() local containers = {} local env = Env() if type(env.gethui) == "function" then local ok, result = pcall(env.gethui) if ok and typeof(result) == "Instance" then table.insert(containers, result) end end table.insert(containers, CoreGui) local player = Players.LocalPlayer local playerGui = player and player:FindFirstChildOfClass("PlayerGui") if playerGui then table.insert(containers, playerGui) end for _, container in ipairs(containers) do local ok, children = pcall(function() return container:GetChildren() end) if ok then for _, child in ipairs(children) do if child:IsA("ScreenGui") and child.Name:find("^Excalibur_") then pcall(function() child:Destroy() end) end end end end end do local env = Env() local previous = env.__ExcaliburActive if type(previous) == "table" and type(previous.Unload) == "function" then pcall(previous.Unload, previous) end PurgeStaleInterfaces() env.__ExcaliburActive = Excalibur end return Excalibur