local __modules = {} local __cache = {} local function import(path) local cached = __cache[path] if cached ~= nil then return cached end local loader = __modules[path] if not loader then error("module not found: " .. tostring(path)) end local value = loader() __cache[path] = value return value end __modules["components/nothing.com/yeahnothing"] = function() end __modules["components/window/dialog"] = function() -- was been removed from ui and not working anymore, dont try to add back pls local Dialog = {} function Dialog.new(ctx, callbacks) callbacks = callbacks or {} local C = ctx.C local make, frame, text, round = ctx.make, ctx.frame, ctx.text, ctx.round local tween, prep, fade = ctx.tween, ctx.prep, ctx.fade local state, Images, FONT_BOLD = ctx.state, ctx.images, ctx.FONT_BOLD local popup = make("Frame", { Size = UDim2.new(1, 0, 1, 0), BackgroundTransparency = 1, BorderSizePixel = 0, ZIndex = 10, Visible = false, }, ctx.canvas) local dim = make("TextButton", { Size = UDim2.new(1, 0, 1, 0), BackgroundColor3 = Color3.fromRGB(0, 0, 0), BackgroundTransparency = 0.4, BorderSizePixel = 0, AutoButtonColor = false, Text = "", }, popup) make("UICorner", { CornerRadius = UDim.new(0, 10) }, dim) local popupCard = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, 270, 0, 132), BackgroundColor3 = "card", BorderSizePixel = 0, }, popup) round(popupCard, 12, "stroke") local badge = frame(popupCard, 22, 20, 32, 32, "input", 0) round(badge, 16, "stroke") make("ImageLabel", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, 12, 0, 12), BackgroundTransparency = 1, Image = Images.CLOSE_ICON, ImageColor3 = ctx.tintIcons and "accent" or Color3.fromRGB(255, 255, 255), }, badge) local popupTitle = text(popupCard, "Close Key System?", 66, 19, 182, 16, 14, "text") popupTitle.FontFace = FONT_BOLD local popupDesc = text(popupCard, "Are you sure you want to close the Key System?", 66, 38, 182, 30, 12, "muted") popupDesc.TextWrapped = true popupDesc.TextYAlignment = Enum.TextYAlignment.Top local function popupButton(label, x, primary) local btn = make("TextButton", { Position = UDim2.new(0, x, 0, 86), Size = UDim2.new(0, 109, 0, 32), BackgroundColor3 = primary and "submitBg" or "btn2", BackgroundTransparency = primary and 0.12 or 0, BorderSizePixel = 0, AutoButtonColor = false, Text = label, TextSize = 13, TextColor3 = primary and "submitText" or "text", FontFace = ctx.FONT, }, popupCard) if primary then round(btn, 8) else round(btn, 8, "stroke") end return btn end local cancelBtn = popupButton("Cancel", 22, false) local confirmBtn = popupButton("Close", 139, true) cancelBtn.MouseEnter:Connect(function() if state.closing or not state.popupOpen then return end tween(cancelBtn, 0.15, { BackgroundColor3 = C.btn2Hover }) end) cancelBtn.MouseLeave:Connect(function() if state.closing or not state.popupOpen then return end tween(cancelBtn, 0.15, { BackgroundColor3 = C.btn2 }) end) confirmBtn.MouseEnter:Connect(function() if state.closing or not state.popupOpen then return end tween(confirmBtn, 0.15, { BackgroundTransparency = 0 }) end) confirmBtn.MouseLeave:Connect(function() if state.closing or not state.popupOpen then return end tween(confirmBtn, 0.15, { BackgroundTransparency = 0.12 }) end) local popupItems = prep(popup) fade(popupItems, 0) local function show() if not state.ready or state.popupOpen or state.closing then return end state.popupOpen = true popup.Visible = true popupCard.Position = UDim2.new(0.5, 0, 0.5, 8) if callbacks.onOpen then callbacks.onOpen() end fade(popupItems, 1, 0.22) tween(popupCard, 0.35, { Position = UDim2.new(0.5, 0, 0.5, 0) }, Enum.EasingStyle.Quint) end local function hide() if not state.popupOpen or state.closing then return end state.popupOpen = false fade(popupItems, 0, 0.18) task.delay(0.2, function() if not state.popupOpen then popup.Visible = false end end) end cancelBtn.MouseButton1Click:Connect(hide) confirmBtn.MouseButton1Click:Connect(function() if callbacks.onConfirm then callbacks.onConfirm() end end) return { popup = popup, items = popupItems, show = show, hide = hide, } end return Dialog end __modules["components/window/notification"] = function() local Lighting = game:GetService("Lighting") local Notification = {} -- NotifStyle: "1" Stripe | "2" Pill | "3" Island | "4" Ring | "5" Solid (names work too) local STYLE_BY_NAME = { stripe = "1", pill = "2", island = "3", ring = "4", solid = "5" } function Notification.new(ctx) local C = ctx.C local make, frame, text, round = ctx.make, ctx.frame, ctx.text, ctx.round local tween, prep, fade = ctx.tween, ctx.prep, ctx.fade local root, cfg, Images = ctx.root, ctx.cfg, ctx.images local FONT, FONT_BOLD = ctx.FONT, ctx.FONT_BOLD local markBoldFont = ctx.markBoldFont local NOTIF_W = cfg.NOTIF_W local NOTIF_TRANSPARENCY = cfg.NOTIF_TRANSPARENCY local NOTIF_COLOR = cfg.NOTIF_COLOR local NOTIF_BLUR = cfg.NOTIF_BLUR local ISLAND_W = 260 local RING_DOTS = 28 local MAX_NOTIFS = 4 local WHITE = Color3.fromRGB(255, 255, 255) local DARK = Color3.fromRGB(11, 11, 11) local ICONS = { key = { Images.KEY, 18 }, submit = { Images.SUBMIT, 18 }, link = { Images.LINK, 18 }, discord = { Images.DISCORD, 18 }, close = { Images.CLOSE_ICON, 14 }, moon = { Images.MOON_ICON, 14 }, } local function kindColor(kind) if kind == "success" then return C.success elseif kind == "warn" then return C.warn elseif kind == "error" then return C.error end return C.accent end -- Readable icon/text color on top of a filled color local function contrastOn(color) local luminance = 0.299 * color.R + 0.587 * color.G + 0.114 * color.B return luminance > 0.55 and DARK or WHITE end local function cardHover() return NOTIF_COLOR == "bg" and C.card or C.btn2 end -- Bottom-right stack (Stripe, Pill, Ring, Solid) local cornerHolder = make("Frame", { AnchorPoint = Vector2.new(1, 1), Position = UDim2.new(1, -16, 1, -8), Size = UDim2.new(0, NOTIF_W, 1, -16), BackgroundTransparency = 1, BorderSizePixel = 0, ZIndex = 20, }, root) make("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, VerticalAlignment = Enum.VerticalAlignment.Bottom, HorizontalAlignment = Enum.HorizontalAlignment.Right, }, cornerHolder) -- Top-center stack (Island) local islandHolder = make("Frame", { AnchorPoint = Vector2.new(0.5, 0), Position = UDim2.new(0.5, 0, 0, 12), Size = UDim2.new(0, ISLAND_W, 1, -24), BackgroundTransparency = 1, BorderSizePixel = 0, ZIndex = 20, }, root) make("UIListLayout", { SortOrder = Enum.SortOrder.LayoutOrder, VerticalAlignment = Enum.VerticalAlignment.Top, HorizontalAlignment = Enum.HorizontalAlignment.Center, }, islandHolder) local notifCount = 0 local activeNotifs = {} local Blur = { effect = nil, users = 0 } function Blur.to(size, time) if NOTIF_BLUR <= 0 then return end if not Blur.effect then local ok, effect = pcall(function() local e = Instance.new("BlurEffect") e.Name = "AirflowBlur" e.Size = 0 e.Parent = Lighting return e end) if not ok then return end Blur.effect = effect end tween(Blur.effect, time, { Size = size }) end function Blur.acquire() Blur.users += 1 Blur.to(NOTIF_BLUR, 0.35) end function Blur.release() Blur.users = math.max(Blur.users - 1, 0) if Blur.users == 0 and Blur.effect then Blur.to(0, 0.5) end end root.Destroying:Connect(function() if Blur.effect then Blur.effect:Destroy() Blur.effect = nil end end) -- Shared builders local function newWrapper(holder, width, height) return make("Frame", { LayoutOrder = notifCount, Size = UDim2.new(0, width, 0, height + 8), BackgroundTransparency = 1, BorderSizePixel = 0, }, holder) end local function newToast(wrapper, props, radius, strokeColor) props.BorderSizePixel = 0 props.AutoButtonColor = false props.ClipsDescendants = true props.Text = "" local toast = make("TextButton", props, wrapper) round(toast, radius, strokeColor) local stroke = toast:FindFirstChildOfClass("UIStroke") if stroke then stroke.ApplyStrokeMode = Enum.ApplyStrokeMode.Border stroke.Transparency = 0.35 end return toast end local function label(parent, str, x, y, w, h, size, color, bold) local l = text(parent, str, x, y, w, h, size, color) if bold then -- Route through markBoldFont (not a raw FontFace assign) so this label -- is registered as bold in fontBindings; otherwise the next -- SetUIFont/SetTitleFont call flattens it back to the regular weight. markBoldFont(l) end l.TextTruncate = Enum.TextTruncate.AtEnd return l end local function iconImage(parent, spec, color, size) return make("ImageLabel", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, size, 0, size), BackgroundTransparency = 1, Image = spec[1], ImageColor3 = color, }, parent) end -- 1 · Stripe: color bar on the left + countdown line at the bottom local function buildStripe(title, message, color) local W, H = NOTIF_W, 62 local wrapper = newWrapper(cornerHolder, W, H) local toast = newToast(wrapper, { Position = UDim2.new(0, 40, 0, 0), Size = UDim2.new(0, W, 0, H), BackgroundColor3 = C[NOTIF_COLOR], BackgroundTransparency = NOTIF_TRANSPARENCY, }, 10, C.stroke) round(frame(toast, 8, 10, 3, H - 20, color, 0), 2) label(toast, title, 22, 11, W - 36, 18, 13, C.text, true) label(toast, message, 22, 30, W - 36, 16, 12, C.muted) local trackW = W - 44 round(frame(toast, 22, H - 9, trackW, 2, color, 0.8), 1) local fill = frame(toast, 22, H - 9, trackW, 2, color, 0) round(fill, 1) return { wrapper = wrapper, toast = toast, startPos = UDim2.new(0, 40, 0, 0), restPos = UDim2.new(0, 0, 0, 0), baseColor = C[NOTIF_COLOR], hoverColor = cardHover(), progress = function(fraction) tween( fill, 0.06, { Size = UDim2.new(0, math.floor(trackW * fraction), 0, 2) }, Enum.EasingStyle.Linear ) end, } end -- 2 · Pill: compact capsule; long text wraps to more lines (never cut) local function escapeRich(str) return (str:gsub("&", "&"):gsub("<", "<"):gsub(">", ">")) end local function buildPill(title, message, color, spec) local H = 36 local wrapper = make("Frame", { LayoutOrder = notifCount, Size = UDim2.new(0, NOTIF_W, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundTransparency = 1, BorderSizePixel = 0, }, cornerHolder) make("UIPadding", { PaddingBottom = UDim.new(0, 8) }, wrapper) local toast = newToast(wrapper, { AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, 40, 0, 0), Size = UDim2.new(0, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.XY, BackgroundColor3 = C[NOTIF_COLOR], BackgroundTransparency = NOTIF_TRANSPARENCY, }, H / 2, C.stroke) make("UISizeConstraint", { MinSize = Vector2.new(0, H) }, toast) make("UIPadding", { PaddingLeft = UDim.new(0, 6), PaddingRight = UDim.new(0, 14), PaddingTop = UDim.new(0, 6), PaddingBottom = UDim.new(0, 6), }, toast) make("UIListLayout", { FillDirection = Enum.FillDirection.Horizontal, VerticalAlignment = Enum.VerticalAlignment.Center, SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 8), }, toast) local badge = make("Frame", { LayoutOrder = 1, Size = UDim2.new(0, 24, 0, 24), BackgroundColor3 = color, BorderSizePixel = 0, }, toast) make("UICorner", { CornerRadius = UDim.new(1, 0) }, badge) iconImage(badge, spec, contrastOn(color), math.min(spec[2], 14)) local rich = "" .. escapeRich(title) .. "" if message ~= "" then rich = rich .. ' ' .. escapeRich(message) .. "" end local body = make("TextLabel", { LayoutOrder = 2, Size = UDim2.new(0, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.XY, BackgroundTransparency = 1, BorderSizePixel = 0, RichText = true, TextWrapped = true, Text = rich, TextSize = 13, TextColor3 = C.text, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Center, FontFace = FONT, }, toast) make("UISizeConstraint", { MaxSize = Vector2.new(NOTIF_W - 52, math.huge) }, body) return { wrapper = wrapper, toast = toast, startPos = UDim2.new(1, 40, 0, 0), restPos = UDim2.new(1, 0, 0, 0), baseColor = C[NOTIF_COLOR], hoverColor = cardHover(), } end -- 3 · Island: dark capsule at the top center that expands in local function buildIsland(title, message, color, spec) local W, H = ISLAND_W, 52 local border = Color3.fromRGB(42, 42, 48) local wrapper = newWrapper(islandHolder, W, H) local toast = newToast(wrapper, { AnchorPoint = Vector2.new(0.5, 0), Position = UDim2.new(0.5, 0, 0, -70), Size = UDim2.new(0, H, 0, H), BackgroundColor3 = Color3.fromRGB(0, 0, 0), BackgroundTransparency = 0.06, }, H / 2, border) local badge = frame(toast, 10, 10, 32, 32, color, 0) make("UICorner", { CornerRadius = UDim.new(1, 0) }, badge) iconImage(badge, spec, contrastOn(color), spec[2]) label(toast, title, 54, 9, W - 70, 16, 13, Color3.fromRGB(244, 244, 245), true) label(toast, message, 54, 27, W - 70, 14, 12, Color3.fromRGB(154, 154, 162)) return { wrapper = wrapper, toast = toast, baseColor = Color3.fromRGB(0, 0, 0), hoverColor = Color3.fromRGB(22, 22, 26), enter = function(items) fade(items, 1, 0.25) tween(toast, 0.4, { Position = UDim2.new(0.5, 0, 0, 0) }, Enum.EasingStyle.Quint) task.delay(0.12, function() tween(toast, 0.5, { Size = UDim2.new(0, W, 0, H) }, Enum.EasingStyle.Quint) end) end, leave = function(items) fade(items, 0, 0.25) tween( toast, 0.3, { Size = UDim2.new(0, H, 0, H) }, Enum.EasingStyle.Quint, Enum.EasingDirection.In ) task.delay(0.15, function() tween( toast, 0.3, { Position = UDim2.new(0.5, 0, 0, -70) }, Enum.EasingStyle.Quint, Enum.EasingDirection.In ) end) end, } end -- 4 · Ring: icon inside a circular timer local function buildRing(title, message, color, spec) local W, H = NOTIF_W, 60 local wrapper = newWrapper(cornerHolder, W, H) local toast = newToast(wrapper, { Position = UDim2.new(0, 40, 0, 0), Size = UDim2.new(0, W, 0, H), BackgroundColor3 = C[NOTIF_COLOR], BackgroundTransparency = NOTIF_TRANSPARENCY, }, 10, C.stroke) local ringBox = frame(toast, 10, 10, 40, 40) local dots = {} for i = 0, RING_DOTS - 1 do local angle = (i / RING_DOTS) * math.pi * 2 - math.pi / 2 local dot = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5 + math.cos(angle) * 0.425, 0, 0.5 + math.sin(angle) * 0.425, 0), Size = UDim2.new(0, 3, 0, 3), BackgroundColor3 = color, BorderSizePixel = 0, }, ringBox) make("UICorner", { CornerRadius = UDim.new(1, 0) }, dot) dots[#dots + 1] = dot end iconImage(ringBox, spec, ctx.tintIcons and color or WHITE, math.min(spec[2], 18)) label(toast, title, 62, 11, W - 76, 18, 13, C.text, true) label(toast, message, 62, 31, W - 76, 16, 12, C.muted) local lastLit = RING_DOTS return { wrapper = wrapper, toast = toast, startPos = UDim2.new(0, 40, 0, 0), restPos = UDim2.new(0, 0, 0, 0), baseColor = C[NOTIF_COLOR], hoverColor = cardHover(), progress = function(fraction) local lit = math.ceil(fraction * RING_DOTS) if lit >= lastLit then return end for i = lit + 1, lastLit do tween(dots[i], 0.15, { BackgroundTransparency = 0.82 }) end lastLit = lit end, } end -- 5 · Solid: filled with the status color local function buildSolid(title, message, color, spec) local W, H = NOTIF_W, 58 local onColor = contrastOn(color) local wrapper = newWrapper(cornerHolder, W, H) local toast = newToast(wrapper, { Position = UDim2.new(0, 40, 0, 0), Size = UDim2.new(0, W, 0, H), BackgroundColor3 = color, BackgroundTransparency = 0.04, }, 10, nil) local iconBox = frame(toast, 14, (H - 22) / 2, 22, 22) iconImage(iconBox, spec, onColor, math.min(spec[2] + 4, 22)) label(toast, title, 48, 10, W - 62, 18, 13, onColor, true) label(toast, message, 48, 30, W - 62, 16, 12, onColor:Lerp(color, 0.35)) return { wrapper = wrapper, toast = toast, startPos = UDim2.new(0, 40, 0, 0), restPos = UDim2.new(0, 0, 0, 0), baseColor = color, hoverColor = color:Lerp(WHITE, 0.12), } end local STYLES = { ["1"] = buildStripe, ["2"] = buildPill, ["3"] = buildIsland, ["4"] = buildRing, ["5"] = buildSolid, } local function resolveKey() local raw = ctx.getStyle and ctx.getStyle() or "1" local key = (tostring(raw):lower():gsub("%s+", "")) key = STYLE_BY_NAME[key] or key return STYLES[key] and key or "1" end local function resolveStyle() return STYLES[resolveKey()] end local function notify(title, message, kind, iconKey, duration) kind = kind or "info" duration = duration or 3.5 title = tostring(title or "") message = tostring(message or "") local color = kindColor(kind) local spec = ICONS[iconKey] or (kind == "error" and ICONS.close or ICONS.key) notifCount += 1 Blur.acquire() local n = resolveStyle()(title, message, color, spec) local wrapper, toast = n.wrapper, n.toast local items = prep(toast) fade(items, 0) local handle = {} local dismissed = false function handle.dismiss() if dismissed then return end dismissed = true Blur.release() local idx = table.find(activeNotifs, handle) if idx then table.remove(activeNotifs, idx) end if n.leave then n.leave(items) else fade(items, 0, 0.25) tween(toast, 0.3, { Position = n.startPos }, Enum.EasingStyle.Quint, Enum.EasingDirection.In) end task.delay(0.28, function() local size = wrapper.Size local height = wrapper.AbsoluteSize.Y wrapper.AutomaticSize = Enum.AutomaticSize.None wrapper.Size = UDim2.new(size.X.Scale, size.X.Offset, 0, height) tween(wrapper, 0.2, { Size = UDim2.new(size.X.Scale, size.X.Offset, 0, 0) }) task.delay(0.22, function() wrapper:Destroy() end) end) end toast.MouseButton1Click:Connect(handle.dismiss) if n.enter then n.enter(items) else fade(items, 1, 0.3) tween(toast, 0.45, { Position = n.restPos }, Enum.EasingStyle.Quint) end local hovering, hoverSince = false, 0 toast.MouseEnter:Connect(function() if dismissed then return end hovering = true hoverSince = os.clock() tween(toast, 0.15, { BackgroundColor3 = n.hoverColor }) end) toast.MouseLeave:Connect(function() if dismissed then return end hovering = false tween(toast, 0.15, { BackgroundColor3 = n.baseColor }) end) task.spawn(function() local remaining = duration local started = os.clock() local last = started while not dismissed do task.wait(0.05) local now = os.clock() if not (hovering and now - hoverSince < 8) then remaining -= now - last end last = now if n.progress and now - started > 0.35 then n.progress(math.clamp(remaining / duration, 0, 1)) end if remaining <= 0 then handle.dismiss() break end end end) table.insert(activeNotifs, handle) while #activeNotifs > MAX_NOTIFS do activeNotifs[1].dismiss() end return handle end local function dismissAll() for i = #activeNotifs, 1, -1 do activeNotifs[i].dismiss() end end return { notify = notify, dismissAll = dismissAll, styleKey = resolveKey, blur = Blur, } end return Notification end __modules["components/window/pages"] = function() -- src/components/window/pages.lua -- Page 2 of the window. It sits right below the Key System: a down arrow at the bottom -- of the Key System slides the Key System up and brings this page in (a topbar, the Tabs -- under it, and the content of the selected Tab: Sections and Paragraphs). -- -- local OphynWindow = KeySystem.new({ ... }) -- -- local Tab = OphynWindow({ Title = "Main", Icon = "rbxassetid://..." }) -- -- Tab:Section({ Title = "Section", Icon = "rbxassetid://..." }) -- -- -- Tabs style: KeySystem:SetTabsStyle("1") = column on the left (default), -- -- KeySystem:SetTabsStyle("2") = row right under the topbar. -- -- -- Every Icon also accepts a Lucide icon name (https://lucide.dev/icons), loaded from -- -- github.com/Footagesus/Icons the first time one is used: -- local Tab = OphynWindow({ Title = "Main", Icon = "house" }) -- Tab:Section({ Title = "Section", Icon = "lucide:settings" }) -- -- Tab:Paragraph({ -- Title = "Paragraph", -- Desc = "Test Paragraph", -- Color = "Red", -- leave it blank to follow the theme -- Buttons = { { Icon = "rbxassetid://...", Title = "Button 1", Callback = function() end } }, -- }) local Pages = {} local NAMED_COLORS = { red = Color3.fromRGB(229, 57, 53), orange = Color3.fromRGB(245, 124, 0), yellow = Color3.fromRGB(250, 204, 21), green = Color3.fromRGB(34, 160, 80), teal = Color3.fromRGB(20, 160, 150), cyan = Color3.fromRGB(6, 182, 212), blue = Color3.fromRGB(59, 130, 246), indigo = Color3.fromRGB(99, 102, 241), purple = Color3.fromRGB(147, 51, 234), pink = Color3.fromRGB(236, 72, 153), grey = Color3.fromRGB(100, 100, 108), gray = Color3.fromRGB(100, 100, 108), white = Color3.fromRGB(245, 245, 245), black = Color3.fromRGB(16, 16, 16), } -- Accepts a Color3, a color name ("Red", "Blue", ...) or a hex string ("#RRGGBB"). -- Returns nil for anything else, which makes the Paragraph follow the theme. local function parseColor(value) if value == nil or value == "" then return nil end if typeof(value) == "Color3" then return value end if type(value) == "string" then local named = NAMED_COLORS[value:lower()] if named then return named end local hex = value:match("^#?(%x%x%x%x%x%x)$") if hex then return Color3.fromHex(hex) end end return nil end function Pages.new(ctx) local C, make, round = ctx.C, ctx.make, ctx.round local tween, prep, fade = ctx.tween, ctx.prep, ctx.fade local setRole, icon, assetId = ctx.setRole, ctx.icon, ctx.assetId local contrastOn, iconRole, logoRole = ctx.contrastOn, ctx.iconRole, ctx.logoRole local FONT, FONT_BOLD, Images = ctx.FONT, ctx.FONT_BOLD, ctx.images local state, content, canvas = ctx.state, ctx.content, ctx.canvas local W, H = ctx.width, ctx.height local TOPBAR_H = 38 local SIDE_W = 124 local SLIDE_TIME = 0.55 local Quint = Enum.EasingStyle.Quint -- Section title look: a bit bigger than before and slightly see-through local SECTION_TEXT_SIZE = 15 local SECTION_TEXT_TRANSPARENCY = 0.35 -- Switching Tabs: the content rises a few pixels while its elements fade in one after -- the other (the stagger is capped so a Tab with many elements doesn't feel slow) local TAB_SLIDE = 10 local TAB_IN_TIME = 0.32 local TAB_STAGGER = 0.045 local TAB_STAGGER_MAX = 0.4 -- Both arrows (down: show the Tabs / up: back to the Key System) reuse the Submit -- button's icon. If that icon points right, 90 turns it to point down and -90 up; -- change this if the arrows end up facing the wrong way. local NEXT_ARROW_ROTATION = 90 local BACK_ARROW_ROTATION = -NEXT_ARROW_ROTATION -- Tabs style 2 (a row under the topbar) local TABS_BAR_H = 34 local TAB_H_STYLE2 = 26 -- false when "Change icons color" is off: icons stay white and are never recolored local tintIcons = type(iconRole("muted")) == "string" -- The arrows: the Submit button's icon in one single ImageLabel, rotated on the label -- itself (not on a parent frame) and placed with plain offsets, so it renders right -- from the first frame. `drop` pushes it down a few pixels inside its button. local function arrowIcon(parent, rotation, drop) local img = make("ImageLabel", { Name = "ArrowIcon", Position = UDim2.new(0.5, -8, 0.5, -8 + (drop or 0)), Size = UDim2.new(0, 16, 0, 16), BackgroundTransparency = 1, Image = Images.SUBMIT, ImageColor3 = iconRole("muted"), Rotation = rotation, ZIndex = 6, }, parent) task.spawn(function() pcall(function() game:GetService("ContentProvider"):PreloadAsync({ img }) end) end) return img end local function tintArrow(img, color) if tintIcons then tween(img, 0.15, { ImageColor3 = color }) end end local function line(parent, x, y, w, h) return make("Frame", { Position = UDim2.new(0, x, 0, y), Size = UDim2.new(0, w, 0, h), BackgroundColor3 = "stroke", BackgroundTransparency = 0, BorderSizePixel = 0, }, parent) end --------------------------------------------------------------------------- -- The page itself: starts one window-height below, hidden --------------------------------------------------------------------------- local page = make("Frame", { Name = "Page2", AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, H), Size = UDim2.new(0, W, 0, H), BackgroundTransparency = 1, BorderSizePixel = 0, Visible = false, }, canvas) -- Topbar: logo + title on the left, back arrow + close on the right local topbar = make("Frame", { Name = "Topbar", Size = UDim2.new(0, W, 0, TOPBAR_H), BackgroundTransparency = 1, BorderSizePixel = 0, }, page) make("ImageLabel", { Position = UDim2.new(0, 14, 0, 9), Size = UDim2.new(0, 24, 0, 20), BackgroundTransparency = 1, Image = ctx.logo, ImageColor3 = logoRole("accent"), ScaleType = Enum.ScaleType.Fit, }, topbar) local pageTitle = make("TextLabel", { Position = UDim2.new(0, 46, 0, 0), Size = UDim2.new(0, W - 46 - 84, 1, 0), BackgroundTransparency = 1, BorderSizePixel = 0, Text = ctx.title, TextSize = 14, TextColor3 = "text", TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Center, TextTruncate = Enum.TextTruncate.AtEnd, FontFace = FONT_BOLD, }, topbar) ctx.markTitleFont(pageTitle) local function topButton(rightOffset) local btn = make("TextButton", { Name = "TopButton", AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, -rightOffset, 0, 6), Size = UDim2.new(0, 26, 0, 26), BackgroundColor3 = "card", BackgroundTransparency = 1, BorderSizePixel = 0, AutoButtonColor = false, Text = "", ZIndex = 5, }, topbar) make("UICorner", { CornerRadius = UDim.new(0, 7) }, btn) return btn end local closeBtn = topButton(12) local closeIcon = make("ImageLabel", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, 12, 0, 12), BackgroundTransparency = 1, Image = Images.CLOSE_ICON, ImageColor3 = iconRole("muted"), ZIndex = 6, }, closeBtn) local backBtn = topButton(40) local backIcon = arrowIcon(backBtn, BACK_ARROW_ROTATION, 0) closeBtn.MouseEnter:Connect(function() tween(closeBtn, 0.15, { BackgroundTransparency = 0 }) if tintIcons then tween(closeIcon, 0.15, { ImageColor3 = C.text }) end end) closeBtn.MouseLeave:Connect(function() tween(closeBtn, 0.15, { BackgroundTransparency = 1 }) if tintIcons then tween(closeIcon, 0.15, { ImageColor3 = C.muted }) end end) backBtn.MouseEnter:Connect(function() tween(backBtn, 0.15, { BackgroundTransparency = 0 }) tintArrow(backIcon, C.text) end) backBtn.MouseLeave:Connect(function() tween(backBtn, 0.15, { BackgroundTransparency = 1 }) tintArrow(backIcon, C.muted) end) -- Tabs style: "1" = column on the left, "2" = row right under the topbar local tabsStyle = "1" local function normalizeStyle(value) value = tostring(value or "1"):lower() if value == "2" or value == "horizontal" or value == "row" then return "2" end return "1" end if ctx.getTabsStyle then tabsStyle = normalizeStyle(ctx.getTabsStyle()) end -- Style 1 draws the line under the topbar; style 2 draws it under the row of Tabs local topLine = line(page, 14, TOPBAR_H, W - 28, 1) local tabsLine = line(page, 14, TOPBAR_H + TABS_BAR_H, W - 28, 1) local sideLine = line(page, SIDE_W, TOPBAR_H + 10, 1, H - TOPBAR_H - 20) -- Tabs (a column in style 1, a row in style 2) local sidebar = make("ScrollingFrame", { Name = "Tabs", BackgroundTransparency = 1, BorderSizePixel = 0, CanvasSize = UDim2.new(0, 0, 0, 0), ElasticBehavior = Enum.ElasticBehavior.Never, ScrollBarThickness = 0, }, page) local sideLayout = make("UIListLayout", { Padding = UDim.new(0, 4), SortOrder = Enum.SortOrder.LayoutOrder, }, sidebar) local sidePadding = make("UIPadding", {}, sidebar) -- Where the selected Tab's content shows up local holder = make("Frame", { Name = "TabContent", BackgroundTransparency = 1, BorderSizePixel = 0, ClipsDescendants = true, }, page) -- mouse wheel scrolls the row sideways in style 2 sidebar.InputChanged:Connect(function(input) if tabsStyle == "2" and input.UserInputType == Enum.UserInputType.MouseWheel then local maxX = math.max(0, sidebar.AbsoluteCanvasSize.X - sidebar.AbsoluteWindowSize.X) local x = sidebar.CanvasPosition.X - input.Position.Z * 30 sidebar.CanvasPosition = Vector2.new(math.clamp(x, 0, maxX), 0) end end) local tabs = {} local current = nil local function applyTabsStyle() local row = tabsStyle == "2" topLine.Visible = not row sideLine.Visible = not row tabsLine.Visible = row sidebar.CanvasPosition = Vector2.new(0, 0) sidebar.AutomaticCanvasSize = Enum.AutomaticSize.None sidebar.CanvasSize = UDim2.new(0, 0, 0, 0) if row then sidebar.Position = UDim2.new(0, 0, 0, TOPBAR_H) sidebar.Size = UDim2.new(0, W, 0, TABS_BAR_H) sidebar.ScrollingDirection = Enum.ScrollingDirection.X sidebar.AutomaticCanvasSize = Enum.AutomaticSize.X sideLayout.FillDirection = Enum.FillDirection.Horizontal sideLayout.VerticalAlignment = Enum.VerticalAlignment.Center sidePadding.PaddingTop = UDim.new(0, 0) sidePadding.PaddingBottom = UDim.new(0, 0) sidePadding.PaddingLeft = UDim.new(0, 12) sidePadding.PaddingRight = UDim.new(0, 12) holder.Position = UDim2.new(0, 0, 0, TOPBAR_H + TABS_BAR_H + 1) holder.Size = UDim2.new(0, W, 0, H - TOPBAR_H - TABS_BAR_H - 1) else sidebar.Position = UDim2.new(0, 0, 0, TOPBAR_H + 1) sidebar.Size = UDim2.new(0, SIDE_W, 0, H - TOPBAR_H - 1) sidebar.ScrollingDirection = Enum.ScrollingDirection.Y sidebar.AutomaticCanvasSize = Enum.AutomaticSize.Y sideLayout.FillDirection = Enum.FillDirection.Vertical sideLayout.VerticalAlignment = Enum.VerticalAlignment.Top sidePadding.PaddingTop = UDim.new(0, 10) sidePadding.PaddingBottom = UDim.new(0, 10) sidePadding.PaddingLeft = UDim.new(0, 10) sidePadding.PaddingRight = UDim.new(0, 10) holder.Position = UDim2.new(0, SIDE_W + 1, 0, TOPBAR_H + 1) holder.Size = UDim2.new(0, W - SIDE_W - 1, 0, H - TOPBAR_H - 1) end for _, tab in ipairs(tabs) do tab.applyStyle() end if current then current.refresh() end end --------------------------------------------------------------------------- -- Sliding between the Key System and this page --------------------------------------------------------------------------- local opened, moving = false, false local function open() if opened or moving then return end opened, moving = true, true if ctx.onOpen then ctx.onOpen() end if current then current.refresh() end page.Visible = true tween(page, SLIDE_TIME, { Position = UDim2.new(0.5, 0, 0.5, 0) }, Quint) tween(content, SLIDE_TIME, { Position = UDim2.new(0.5, 0, 0.5, -H) }, Quint) task.delay(SLIDE_TIME + 0.05, function() moving = false end) end local function back() if not opened or moving then return end opened, moving = false, true tween(page, SLIDE_TIME, { Position = UDim2.new(0.5, 0, 0.5, H) }, Quint) tween(content, SLIDE_TIME, { Position = UDim2.new(0.5, 0, 0.5, 0) }, Quint) task.delay(SLIDE_TIME + 0.05, function() if not opened then page.Visible = false end moving = false end) end -- Used when the whole UI closes while this page is showing local function fadeOut(time) if not page.Visible then return end fade(prep(page), 0, time) task.delay(time, function() page.Visible = false end) end -- The down arrow, in the middle of the bottom of the Key System. It only shows up -- once there is at least one Tab, so a script that never creates one doesn't end up -- with an arrow that leads to an empty page. local nextBtn = make("TextButton", { Name = "NextPage", AnchorPoint = Vector2.new(0.5, 1), Position = UDim2.new(0, W / 2, 0, H - 2), Size = UDim2.new(0, 40, 0, 20), BackgroundTransparency = 1, BorderSizePixel = 0, AutoButtonColor = false, Text = "", Visible = false, ZIndex = 5, }, content) -- Same icon as the Submit button (Images.SUBMIT), turned to point down local nextIcon = arrowIcon(nextBtn, NEXT_ARROW_ROTATION, 2) nextBtn.MouseEnter:Connect(function() tintArrow(nextIcon, C.text) end) nextBtn.MouseLeave:Connect(function() tintArrow(nextIcon, C.muted) end) nextBtn.MouseButton1Click:Connect(function() if not state.ready or state.closing then return end open() end) backBtn.MouseButton1Click:Connect(function() if not state.ready or state.closing then return end back() end) closeBtn.MouseButton1Click:Connect(function() ctx.requestClose() end) --------------------------------------------------------------------------- -- Tabs --------------------------------------------------------------------------- local function styleTab(tab, on) tween(tab.btn, 0.15, { BackgroundTransparency = on and 0 or 1 }) setRole(tab.label, "TextColor3", on and "text" or "muted") if tab.iconImage then local role = iconRole(on and "accent" or "muted") if type(role) == "string" then setRole(tab.iconImage, "ImageColor3", role) end end tab.scroll.Visible = on end -- originals[inst][prop] = the resting transparency of that property, captured only once. -- Switching Tabs quickly (while an animation is still running) then never records a -- half-faded value as the "normal" one. local originals = setmetatable({}, { __mode = "k" }) local function snapshot(child) local items = prep(child) for _, it in ipairs(items) do local saved = originals[it[1]] if not saved then saved = {} originals[it[1]] = saved end if saved[it[2]] == nil then saved[it[2]] = it[3] else it[3] = saved[it[2]] end end return items end -- Plays when a Tab becomes the selected one: the whole content rises a little and -- every element (Section / Paragraph) fades in, one after the other. local function animateIn(tab) tab.animId = (tab.animId or 0) + 1 local id = tab.animId local children = {} for _, child in ipairs(tab.scroll:GetChildren()) do if child:IsA("GuiObject") then children[#children + 1] = child end end table.sort(children, function(a, b) return a.LayoutOrder < b.LayoutOrder end) if #children == 0 then return end local lists = {} for i, child in ipairs(children) do local items = snapshot(child) fade(items, 0) -- start fully transparent lists[i] = items end tab.scroll.Position = UDim2.new(0, 0, 0, TAB_SLIDE) tween(tab.scroll, TAB_IN_TIME + 0.08, { Position = UDim2.new(0, 0, 0, 0) }, Quint) local step = math.min(TAB_STAGGER, TAB_STAGGER_MAX / #children) for i, items in ipairs(lists) do task.delay((i - 1) * step, function() if tab.animId ~= id then return -- a newer animation took over this Tab end fade(items, 1, TAB_IN_TIME) end) end end local function selectTab(tab, animate) if current == tab then return end if current then styleTab(current, false) end current = tab styleTab(tab, true) tab.refresh() if animate ~= false and (opened or page.Visible) then animateIn(tab) end end -- OphynWindow({ Title = "...", Icon = "..." }) -> Tab local function createTab(props) if type(props) ~= "table" then props = { Title = props } end local title = props.Title ~= nil and tostring(props.Title) or "Tab" local image = assetId(props.Icon) local tab = {} -- Tab button: the icon comes first, then the text. The icon + text live in `inner` -- (it holds the layout and the side padding, so the button can size itself to the -- text in style 2). tab.btn = make("TextButton", { Name = "Tab", Size = UDim2.new(1, 0, 0, 30), BackgroundColor3 = "card", BackgroundTransparency = 1, BorderSizePixel = 0, AutoButtonColor = false, Text = "", LayoutOrder = #tabs + 1, }, sidebar) round(tab.btn, 7) tab.inner = make("Frame", { Name = "Inner", Size = UDim2.new(1, 0, 1, 0), BackgroundTransparency = 1, BorderSizePixel = 0, }, tab.btn) tab.pad = make("UIPadding", {}, tab.inner) make("UIListLayout", { FillDirection = Enum.FillDirection.Horizontal, Padding = UDim.new(0, 6), VerticalAlignment = Enum.VerticalAlignment.Center, SortOrder = Enum.SortOrder.LayoutOrder, }, tab.inner) if image then local iconHolder = icon(tab.inner, 0, 0, "muted", image) iconHolder.LayoutOrder = 1 tab.iconImage = iconHolder:FindFirstChild("iconimage") end tab.label = make("TextLabel", { Size = UDim2.new(1, image and -22 or 0, 1, 0), BackgroundTransparency = 1, BorderSizePixel = 0, Text = title, TextSize = 12, TextColor3 = "muted", TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Center, TextTruncate = Enum.TextTruncate.AtEnd, FontFace = FONT, LayoutOrder = 2, }, tab.inner) -- Lays the button out for the current Tabs style (also runs when the style changes) tab.applyStyle = function() if tabsStyle == "2" then tab.btn.Size = UDim2.new(0, 0, 0, TAB_H_STYLE2) tab.btn.AutomaticSize = Enum.AutomaticSize.X tab.inner.Size = UDim2.new(0, 0, 1, 0) tab.inner.AutomaticSize = Enum.AutomaticSize.X tab.pad.PaddingLeft = UDim.new(0, 10) tab.pad.PaddingRight = UDim.new(0, 12) tab.label.Size = UDim2.new(0, 0, 1, 0) tab.label.AutomaticSize = Enum.AutomaticSize.X else tab.btn.AutomaticSize = Enum.AutomaticSize.None tab.btn.Size = UDim2.new(1, 0, 0, 30) tab.inner.AutomaticSize = Enum.AutomaticSize.None tab.inner.Size = UDim2.new(1, 0, 1, 0) tab.pad.PaddingLeft = UDim.new(0, 12) tab.pad.PaddingRight = UDim.new(0, 8) tab.label.AutomaticSize = Enum.AutomaticSize.None tab.label.Size = UDim2.new(1, image and -22 or 0, 1, 0) end end tab.applyStyle() -- The content of this Tab tab.scroll = make("ScrollingFrame", { Name = "TabContent", Size = UDim2.new(1, 0, 1, 0), BackgroundTransparency = 1, BorderSizePixel = 0, CanvasSize = UDim2.new(0, 0, 0, 0), ScrollingDirection = Enum.ScrollingDirection.Y, ElasticBehavior = Enum.ElasticBehavior.Never, VerticalScrollBarInset = Enum.ScrollBarInset.None, ScrollBarThickness = 2, ScrollBarImageTransparency = 0.45, Visible = false, }, holder) setRole(tab.scroll, "ScrollBarImageColor3", "muted") local layout = make("UIListLayout", { Padding = UDim.new(0, 8), SortOrder = Enum.SortOrder.LayoutOrder, }, tab.scroll) make("UIPadding", { PaddingTop = UDim.new(0, 12), PaddingBottom = UDim.new(0, 12), PaddingLeft = UDim.new(0, 12), PaddingRight = UDim.new(0, 14), }, tab.scroll) tab.refresh = function() tab.scroll.CanvasSize = UDim2.new(0, 0, 0, layout.AbsoluteContentSize.Y + 24) end layout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(tab.refresh) tab.btn.MouseEnter:Connect(function() if current ~= tab then tween(tab.btn, 0.12, { BackgroundTransparency = 0.5 }) end end) tab.btn.MouseLeave:Connect(function() if current ~= tab then tween(tab.btn, 0.12, { BackgroundTransparency = 1 }) end end) tab.btn.MouseButton1Click:Connect(function() if state.closing then return end selectTab(tab) end) tabs[#tabs + 1] = tab if not nextBtn.Visible then nextBtn.Visible = true -- first time the arrow shows up: make the engine request/draw its image again task.defer(function() nextIcon.Image = "" nextIcon.Image = Images.SUBMIT end) end if not current then selectTab(tab, false) end -- Tab:Section / Tab:Paragraph local order = 0 local function nextOrder() order = order + 1 return order end local obj = {} function obj:Select() selectTab(tab) return self end -- Tab:Section({ Title = "...", Icon = "..." }): the icon comes first, then the text function obj:Section(p) p = type(p) == "table" and p or {} local sectionImage = assetId(p.Icon) local row = make("Frame", { Name = "Section", Size = UDim2.new(1, 0, 0, 26), BackgroundTransparency = 1, BorderSizePixel = 0, LayoutOrder = nextOrder(), }, tab.scroll) make("UIListLayout", { FillDirection = Enum.FillDirection.Horizontal, Padding = UDim.new(0, 7), VerticalAlignment = Enum.VerticalAlignment.Center, SortOrder = Enum.SortOrder.LayoutOrder, }, row) if sectionImage then local iconHolder = icon(row, 0, 0, "accent", sectionImage) iconHolder.LayoutOrder = 1 end local label = make("TextLabel", { Size = UDim2.new(1, sectionImage and -23 or 0, 1, 0), BackgroundTransparency = 1, BorderSizePixel = 0, Text = p.Title ~= nil and tostring(p.Title) or "Section", TextSize = SECTION_TEXT_SIZE, TextColor3 = "text", TextTransparency = SECTION_TEXT_TRANSPARENCY, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Center, TextTruncate = Enum.TextTruncate.AtEnd, FontFace = FONT_BOLD, LayoutOrder = 2, }, row) local section = { Frame = row } function section:SetTitle(str) label.Text = tostring(str) return self end function section:Destroy() row:Destroy() end return section end -- Tab:Paragraph({ Title, Desc, Color, Buttons = { { Icon, Title, Callback } } }) function obj:Paragraph(p) p = type(p) == "table" and p or {} local color = parseColor(p.Color) -- nil: follows the theme local onColor = color and contrastOn(color) or nil local box = make("Frame", { Name = "Paragraph", Size = UDim2.new(1, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundColor3 = color or "card", BackgroundTransparency = 0, BorderSizePixel = 0, LayoutOrder = nextOrder(), }, tab.scroll) round(box, 8, (not color) and "stroke" or nil) make("UIPadding", { PaddingTop = UDim.new(0, 10), PaddingBottom = UDim.new(0, 10), PaddingLeft = UDim.new(0, 12), PaddingRight = UDim.new(0, 12), }, box) make("UIListLayout", { Padding = UDim.new(0, 6), SortOrder = Enum.SortOrder.LayoutOrder, }, box) local function paragraphLabel(layoutOrder, size, font, textColor, str, transparency) return make("TextLabel", { Size = UDim2.new(1, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundTransparency = 1, BorderSizePixel = 0, Text = str, TextSize = size, TextColor3 = textColor, TextTransparency = transparency, TextWrapped = true, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, FontFace = font, LayoutOrder = layoutOrder, Visible = str ~= "", }, box) end local titleText = p.Title ~= nil and tostring(p.Title) or "" local descText = p.Desc ~= nil and tostring(p.Desc) or "" local titleLabel = paragraphLabel(1, 13, FONT_BOLD, onColor or "text", titleText, 0) local descLabel = paragraphLabel(2, 12, FONT, onColor or "muted", descText, onColor and 0.2 or 0) local buttons = type(p.Buttons) == "table" and p.Buttons or {} if #buttons > 0 then local row = make("Frame", { Name = "Buttons", Size = UDim2.new(1, 0, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundTransparency = 1, BorderSizePixel = 0, LayoutOrder = 3, }, box) make("UIListLayout", { FillDirection = Enum.FillDirection.Horizontal, Wraps = true, Padding = UDim.new(0, 6), SortOrder = Enum.SortOrder.LayoutOrder, }, row) for i, b in ipairs(buttons) do if type(b) == "table" then local btn = make("TextButton", { Name = "Button", Size = UDim2.new(0, 0, 0, 26), AutomaticSize = Enum.AutomaticSize.X, BackgroundColor3 = color and onColor or "btn2", BackgroundTransparency = color and 0.86 or 0, BorderSizePixel = 0, AutoButtonColor = false, Text = "", LayoutOrder = i, }, row) round(btn, 7, (not color) and "stroke" or nil) make("UIPadding", { PaddingLeft = UDim.new(0, 9), PaddingRight = UDim.new(0, 10), }, btn) make("UIListLayout", { FillDirection = Enum.FillDirection.Horizontal, Padding = UDim.new(0, 6), VerticalAlignment = Enum.VerticalAlignment.Center, SortOrder = Enum.SortOrder.LayoutOrder, }, btn) -- icon first, then the text local buttonImage = assetId(b.Icon) if buttonImage then local iconHolder = icon(btn, 0, 0, onColor or "text", buttonImage) iconHolder.LayoutOrder = 1 end make("TextLabel", { Size = UDim2.new(0, 0, 1, 0), AutomaticSize = Enum.AutomaticSize.X, BackgroundTransparency = 1, BorderSizePixel = 0, Text = b.Title ~= nil and tostring(b.Title) or "Button", TextSize = 12, TextColor3 = onColor or "text", TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Center, FontFace = FONT, LayoutOrder = 2, }, btn) btn.MouseEnter:Connect(function() if color then tween(btn, 0.12, { BackgroundTransparency = 0.72 }) else tween(btn, 0.12, { BackgroundColor3 = C.btn2Hover }) end end) btn.MouseLeave:Connect(function() if color then tween(btn, 0.12, { BackgroundTransparency = 0.86 }) else tween(btn, 0.12, { BackgroundColor3 = C.btn2 }) end end) btn.MouseButton1Click:Connect(function() if state.closing or type(b.Callback) ~= "function" then return end task.spawn(function() local ok, err = pcall(b.Callback) if not ok then warn("[Ophyn] Button callback error: " .. tostring(err)) end end) end) end end end local paragraph = { Frame = box } function paragraph:SetTitle(str) titleLabel.Text = tostring(str) titleLabel.Visible = titleLabel.Text ~= "" return self end function paragraph:SetDesc(str) descLabel.Text = tostring(str) descLabel.Visible = descLabel.Text ~= "" return self end function paragraph:Destroy() box:Destroy() end return paragraph end return obj end applyTabsStyle() -- KeySystem:SetTabsStyle("1" / "2") works before or after the window exists: ui.lua -- calls this applier whenever the style changes. It returns false once the window is gone. if ctx.registerTabsStyle then ctx.registerTabsStyle(function() if not page.Parent then return false end local style = normalizeStyle(ctx.getTabsStyle and ctx.getTabsStyle()) if style ~= tabsStyle then tabsStyle = style applyTabsStyle() end return true end) end return { createTab = createTab, open = open, back = back, fadeOut = fadeOut, isOpen = function() return opened end, } end return Pages end __modules["components/window/ui"] = function() local TweenService = game:GetService("TweenService") local Players = game:GetService("Players") local HttpService = game:GetService("HttpService") local UserInputService = game:GetService("UserInputService") local MarketplaceService = game:GetService("MarketplaceService") local player = Players.LocalPlayer local Images = import("images/images") local Notification = import("components/window/notification") local Variables = import("variables") local Jnkie = import("utilities/jnkie") local Platoboost = import("utilities/platoboost") local Panda = import("utilities/panda") local Pages = import("components/window/pages") local Lucide = import("utilities/lucide") local FONT = Font.new(Images.FONT, Enum.FontWeight.Regular, Enum.FontStyle.Normal) local FONT_BOLD = Font.new(Images.FONT, Enum.FontWeight.Bold, Enum.FontStyle.Normal) local GLOW = Images.GLOW local CLOSE_ICON = Images.CLOSE_ICON local MOON_ICON = Images.MOON_ICON local FINAL_W, FINAL_H = 460, 260 local NOTIF_W, NOTIF_H = 300, 70 local NOTIF_TRANSPARENCY = 0.28 local NOTIF_COLOR = "bg" local NOTIF_BLUR = 6 local CHECK_TIME = 1 local SAVED_CHECK_TIME = 0.15 local WHITE = Color3.fromRGB(255, 255, 255) local settings = { tintIcons = true, tintLogo = true } local function asBool(v, default) if v == nil then return default end if type(v) == "string" then return v:lower() == "true" end return v == true end local function assetId(v) if v == nil or v == "" then return nil end local str = tostring(v) if str:match("^%d+$") then return "rbxassetid://" .. str end return str end local function iconRole(role) return settings.tintIcons and role or WHITE end local function logoRole(role) return settings.tintLogo and role or WHITE end local THEME_ORDER = { "Carmim", "Plant", "Plant-Dark", "Dark", "Light", "Violet", "Midnight", "Amber", "Indigo", "Amethyst", } local THEMES = { Amethyst = { bg = Color3.fromRGB(20, 16, 20), input = Color3.fromRGB(24, 19, 24), card = Color3.fromRGB(28, 22, 28), stroke = Color3.fromRGB(40, 32, 41), btn2 = Color3.fromRGB(42, 36, 43), btn2Hover = Color3.fromRGB(54, 47, 55), text = Color3.fromRGB(233, 229, 234), muted = Color3.fromRGB(125, 115, 126), accent = Color3.fromRGB(235, 199, 246), warn = Color3.fromRGB(240, 176, 108), success = Color3.fromRGB(120, 210, 140), error = Color3.fromRGB(240, 120, 120), submitBg = Color3.fromRGB(235, 199, 246), submitText = Color3.fromRGB(24, 18, 26), glowBase = Color3.fromRGB(226, 218, 230), glowFrom = Color3.fromRGB(255, 255, 255), glowTo = Color3.fromRGB(235, 199, 246), confetti = { Color3.fromRGB(235, 199, 246), Color3.fromRGB(120, 210, 140), Color3.fromRGB(255, 255, 255), Color3.fromRGB(240, 176, 108), Color3.fromRGB(150, 190, 255), }, }, Carmim = { bg = Color3.fromRGB(10, 10, 10), input = Color3.fromRGB(16, 14, 14), card = Color3.fromRGB(20, 17, 17), stroke = Color3.fromRGB(38, 32, 32), btn2 = Color3.fromRGB(32, 28, 28), btn2Hover = Color3.fromRGB(46, 40, 40), text = Color3.fromRGB(240, 236, 236), muted = Color3.fromRGB(130, 122, 122), accent = Color3.fromRGB(230, 45, 55), warn = Color3.fromRGB(240, 176, 108), success = Color3.fromRGB(120, 210, 140), error = Color3.fromRGB(240, 120, 120), submitBg = Color3.fromRGB(139, 17, 27), submitText = Color3.fromRGB(255, 255, 255), glowBase = Color3.fromRGB(255, 120, 120), glowFrom = Color3.fromRGB(255, 90, 90), glowTo = Color3.fromRGB(200, 20, 35), confetti = { Color3.fromRGB(230, 45, 55), Color3.fromRGB(255, 120, 120), Color3.fromRGB(255, 255, 255), Color3.fromRGB(240, 176, 108), Color3.fromRGB(150, 20, 30), }, }, Plant = { bg = Color3.fromRGB(28, 94, 56), input = Color3.fromRGB(23, 78, 46), card = Color3.fromRGB(34, 108, 65), stroke = Color3.fromRGB(58, 140, 92), btn2 = Color3.fromRGB(44, 122, 74), btn2Hover = Color3.fromRGB(56, 140, 88), text = Color3.fromRGB(255, 255, 255), muted = Color3.fromRGB(188, 226, 202), accent = Color3.fromRGB(255, 255, 255), warn = Color3.fromRGB(255, 214, 140), success = Color3.fromRGB(200, 255, 210), error = Color3.fromRGB(255, 150, 150), submitBg = Color3.fromRGB(96, 205, 122), submitText = Color3.fromRGB(14, 66, 36), glowBase = Color3.fromRGB(255, 255, 255), glowFrom = Color3.fromRGB(255, 255, 255), glowTo = Color3.fromRGB(235, 255, 240), confetti = { Color3.fromRGB(255, 255, 255), Color3.fromRGB(150, 235, 170), Color3.fromRGB(96, 205, 122), Color3.fromRGB(255, 214, 140), Color3.fromRGB(210, 255, 220), }, }, ["Plant-Dark"] = { bg = Color3.fromRGB(10, 10, 10), input = Color3.fromRGB(14, 16, 14), card = Color3.fromRGB(18, 22, 19), stroke = Color3.fromRGB(34, 42, 36), btn2 = Color3.fromRGB(28, 34, 29), btn2Hover = Color3.fromRGB(40, 48, 42), text = Color3.fromRGB(238, 242, 238), muted = Color3.fromRGB(122, 132, 124), accent = Color3.fromRGB(70, 214, 110), warn = Color3.fromRGB(240, 176, 108), success = Color3.fromRGB(120, 220, 150), error = Color3.fromRGB(240, 120, 120), submitBg = Color3.fromRGB(22, 101, 52), submitText = Color3.fromRGB(255, 255, 255), glowBase = Color3.fromRGB(110, 255, 150), glowFrom = Color3.fromRGB(90, 240, 130), glowTo = Color3.fromRGB(30, 170, 70), confetti = { Color3.fromRGB(70, 214, 110), Color3.fromRGB(150, 245, 175), Color3.fromRGB(255, 255, 255), Color3.fromRGB(240, 176, 108), Color3.fromRGB(22, 101, 52), }, }, Dark = { bg = Color3.fromRGB(10, 10, 10), input = Color3.fromRGB(18, 18, 18), card = Color3.fromRGB(23, 23, 23), stroke = Color3.fromRGB(46, 46, 46), btn2 = Color3.fromRGB(34, 34, 34), btn2Hover = Color3.fromRGB(48, 48, 48), text = Color3.fromRGB(255, 255, 255), muted = Color3.fromRGB(150, 150, 150), accent = Color3.fromRGB(255, 255, 255), warn = Color3.fromRGB(240, 176, 108), success = Color3.fromRGB(120, 210, 140), error = Color3.fromRGB(240, 120, 120), submitBg = Color3.fromRGB(66, 66, 66), submitText = Color3.fromRGB(255, 255, 255), glowBase = Color3.fromRGB(255, 255, 255), glowFrom = Color3.fromRGB(255, 255, 255), glowTo = Color3.fromRGB(210, 210, 210), confetti = { Color3.fromRGB(255, 255, 255), Color3.fromRGB(200, 200, 200), Color3.fromRGB(140, 140, 140), Color3.fromRGB(240, 176, 108), Color3.fromRGB(120, 210, 140), }, }, Light = { bg = Color3.fromRGB(255, 255, 255), input = Color3.fromRGB(240, 240, 240), card = Color3.fromRGB(245, 245, 245), stroke = Color3.fromRGB(216, 216, 216), btn2 = Color3.fromRGB(232, 232, 232), btn2Hover = Color3.fromRGB(218, 218, 218), text = Color3.fromRGB(10, 10, 10), muted = Color3.fromRGB(110, 110, 110), accent = Color3.fromRGB(10, 10, 10), warn = Color3.fromRGB(196, 116, 24), success = Color3.fromRGB(28, 150, 72), error = Color3.fromRGB(210, 58, 58), submitBg = Color3.fromRGB(20, 20, 20), submitText = Color3.fromRGB(255, 255, 255), glowBase = Color3.fromRGB(30, 30, 30), glowFrom = Color3.fromRGB(60, 60, 60), glowTo = Color3.fromRGB(0, 0, 0), confetti = { Color3.fromRGB(10, 10, 10), Color3.fromRGB(90, 90, 90), Color3.fromRGB(160, 160, 160), Color3.fromRGB(230, 150, 50), Color3.fromRGB(50, 170, 100), }, }, Violet = { bg = Color3.fromRGB(94, 64, 162), input = Color3.fromRGB(78, 52, 140), card = Color3.fromRGB(108, 78, 180), stroke = Color3.fromRGB(136, 108, 204), btn2 = Color3.fromRGB(120, 90, 192), btn2Hover = Color3.fromRGB(136, 106, 208), text = Color3.fromRGB(255, 255, 255), muted = Color3.fromRGB(214, 202, 242), accent = Color3.fromRGB(255, 255, 255), warn = Color3.fromRGB(255, 214, 140), success = Color3.fromRGB(200, 255, 210), error = Color3.fromRGB(255, 160, 170), submitBg = Color3.fromRGB(58, 32, 112), submitText = Color3.fromRGB(255, 255, 255), glowBase = Color3.fromRGB(255, 255, 255), glowFrom = Color3.fromRGB(255, 255, 255), glowTo = Color3.fromRGB(240, 232, 255), confetti = { Color3.fromRGB(255, 255, 255), Color3.fromRGB(214, 190, 255), Color3.fromRGB(170, 130, 255), Color3.fromRGB(255, 214, 140), Color3.fromRGB(58, 32, 112), }, }, Midnight = { bg = Color3.fromRGB(26, 44, 104), input = Color3.fromRGB(18, 32, 80), card = Color3.fromRGB(34, 56, 124), stroke = Color3.fromRGB(62, 88, 158), btn2 = Color3.fromRGB(44, 70, 142), btn2Hover = Color3.fromRGB(58, 86, 164), text = Color3.fromRGB(255, 255, 255), muted = Color3.fromRGB(190, 204, 240), accent = Color3.fromRGB(255, 255, 255), warn = Color3.fromRGB(255, 214, 140), success = Color3.fromRGB(190, 255, 215), error = Color3.fromRGB(255, 150, 160), submitBg = Color3.fromRGB(52, 92, 196), submitText = Color3.fromRGB(255, 255, 255), glowBase = Color3.fromRGB(255, 255, 255), glowFrom = Color3.fromRGB(255, 255, 255), glowTo = Color3.fromRGB(226, 236, 255), confetti = { Color3.fromRGB(255, 255, 255), Color3.fromRGB(170, 200, 255), Color3.fromRGB(100, 150, 255), Color3.fromRGB(255, 214, 140), Color3.fromRGB(52, 92, 196), }, }, Amber = { bg = Color3.fromRGB(160, 84, 16), input = Color3.fromRGB(132, 68, 10), card = Color3.fromRGB(176, 98, 28), stroke = Color3.fromRGB(206, 132, 62), btn2 = Color3.fromRGB(186, 108, 38), btn2Hover = Color3.fromRGB(200, 122, 52), text = Color3.fromRGB(255, 255, 255), muted = Color3.fromRGB(255, 228, 196), accent = Color3.fromRGB(255, 255, 255), warn = Color3.fromRGB(255, 240, 170), success = Color3.fromRGB(215, 255, 205), error = Color3.fromRGB(110, 18, 18), submitBg = Color3.fromRGB(110, 50, 6), submitText = Color3.fromRGB(255, 255, 255), glowBase = Color3.fromRGB(255, 255, 255), glowFrom = Color3.fromRGB(255, 255, 255), glowTo = Color3.fromRGB(255, 240, 220), confetti = { Color3.fromRGB(255, 255, 255), Color3.fromRGB(255, 220, 160), Color3.fromRGB(255, 180, 90), Color3.fromRGB(255, 240, 170), Color3.fromRGB(110, 50, 6), }, }, Indigo = { bg = Color3.fromRGB(20, 14, 58), input = Color3.fromRGB(15, 10, 46), card = Color3.fromRGB(28, 20, 76), stroke = Color3.fromRGB(50, 40, 112), btn2 = Color3.fromRGB(38, 29, 96), btn2Hover = Color3.fromRGB(52, 42, 122), text = Color3.fromRGB(240, 238, 255), muted = Color3.fromRGB(150, 142, 204), accent = Color3.fromRGB(150, 132, 255), warn = Color3.fromRGB(240, 190, 120), success = Color3.fromRGB(120, 220, 160), error = Color3.fromRGB(255, 120, 140), submitBg = Color3.fromRGB(84, 64, 210), submitText = Color3.fromRGB(255, 255, 255), glowBase = Color3.fromRGB(160, 140, 255), glowFrom = Color3.fromRGB(140, 120, 255), glowTo = Color3.fromRGB(90, 70, 230), confetti = { Color3.fromRGB(150, 132, 255), Color3.fromRGB(200, 190, 255), Color3.fromRGB(255, 255, 255), Color3.fromRGB(240, 190, 120), Color3.fromRGB(84, 64, 210), }, }, } local themeIndex = 1 local C = {} local function loadTheme(theme) for k, v in pairs(theme) do C[k] = v end end local COLOR_PROPS = { BackgroundColor3 = true, TextColor3 = true, ImageColor3 = true, Color = true, PlaceholderColor3 = true, } local bindings = {} local gradients = {} -- UI/Title font (Ophyn:SetUIFont / Ophyn:SetTitleFont). Every label built through make() -- with FontFace = FONT or FONT_BOLD is tracked here so both setters can restyle text that -- already exists, not just text built afterwards. local fontBindings = {} local fontSettings = { ui = nil, title = nil } local function fontFor(entryFont) if entryFont.title and fontSettings.title then local t = fontSettings.title if entryFont.bold then return Font.new(t.Family, Enum.FontWeight.Bold, t.Style) end return t end if fontSettings.ui then local u = fontSettings.ui if entryFont.bold then return Font.new(u.Family, Enum.FontWeight.Bold, u.Style) end return u end return entryFont.bold and FONT_BOLD or FONT end local function applyFontAll() for _, entryFont in ipairs(fontBindings) do if entryFont.inst.Parent then entryFont.inst.FontFace = fontFor(entryFont) end end end -- Marks an already-created label as the window title, so SetTitleFont targets only it -- (SetUIFont still applies to it too, as a fallback, same as everything else). local function markTitleFont(inst) for _, entryFont in ipairs(fontBindings) do if entryFont.inst == inst then entryFont.title = true inst.FontFace = fontFor(entryFont) return end end end -- Same idea for a bold label created via text() then switched to FONT_BOLD afterwards, -- so SetUIFont/SetTitleFont don't flatten it back to the regular weight later. local function markBoldFont(inst) for _, entryFont in ipairs(fontBindings) do if entryFont.inst == inst then entryFont.bold = true inst.FontFace = fontFor(entryFont) return end end end -- Accepts a Font instance, a Roblox Enum.Font name ("Gotham", "SourceSansBold", ...), a -- custom font family asset ("rbxassetid://..." or a bare numeric id), or a table -- { Family = ..., Weight = ..., Style = ... }. local function resolveFont(input) if input == nil then return nil end if typeof(input) == "Font" then return input end if type(input) == "table" then return Font.new(input.Family or input.family, input.Weight or Enum.FontWeight.Regular, input.Style or Enum.FontStyle.Normal) end local name = tostring(input) local ok, enumFont = pcall(function() return Enum.Font[name] end) if ok and typeof(enumFont) == "EnumItem" then return Font.fromEnum(enumFont) end local family = name if family:match("^%d+$") then family = "rbxassetid://" .. family end return Font.new(family, Enum.FontWeight.Regular, Enum.FontStyle.Normal) end local function make(class, props, parent) local inst = Instance.new(class) for k, v in pairs(props) do if type(v) == "string" and COLOR_PROPS[k] then bindings[#bindings + 1] = { inst, k, v } inst[k] = C[v] elseif k == "FontFace" and (v == FONT or v == FONT_BOLD) then fontBindings[#fontBindings + 1] = { inst = inst, bold = (v == FONT_BOLD), title = false } inst[k] = v else inst[k] = v end end inst.Parent = parent return inst end local function unbind(inst, prop) for i = #bindings, 1, -1 do local b = bindings[i] if b[1] == inst and b[2] == prop then table.remove(bindings, i) end end end local function setRole(inst, prop, role) local found = false for _, b in ipairs(bindings) do if b[1] == inst and b[2] == prop then b[3] = role found = true break end end if not found then bindings[#bindings + 1] = { inst, prop, role } end inst[prop] = C[role] end local function frame(parent, x, y, w, h, color, transparency) return make("Frame", { Position = UDim2.new(0, x, 0, y), Size = UDim2.new(0, w, 0, h), BackgroundColor3 = color or C.bg, BackgroundTransparency = transparency or 1, BorderSizePixel = 0, }, parent) end local function text(parent, str, x, y, w, h, size, color, align) return make("TextLabel", { Position = UDim2.new(0, x, 0, y), Size = UDim2.new(0, w, 0, h), BackgroundTransparency = 1, BorderSizePixel = 0, Text = str, TextSize = size, TextColor3 = color, TextXAlignment = align or Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Center, FontFace = FONT, }, parent) end local function round(parent, radius, strokeColor) make("UICorner", { CornerRadius = UDim.new(0, radius) }, parent) if strokeColor then make("UIStroke", { Thickness = 1, ApplyStrokeMode = Enum.ApplyStrokeMode.Contextual, Color = strokeColor, }, parent) end end local function icon(parent, x, y, color, image) local holder = frame(parent, x, y, 16, 16) make("ImageLabel", { Name = "iconglow", Size = UDim2.new(2, 0, 2, 0), Position = UDim2.new(0.5, 0, 0.5, 0), AnchorPoint = Vector2.new(0.5, 0.5), BackgroundTransparency = 1, Image = GLOW, ImageColor3 = color, ImageTransparency = 0.9, ZIndex = 0, }, holder) local img = make("ImageLabel", { Name = "iconimage", Size = UDim2.new(1, 0, 1, 0), BackgroundTransparency = 1, ImageColor3 = iconRole(color), }, holder) -- `image` can be an asset id or a Lucide icon name ("house" / "lucide:house") Lucide.apply(img, image) return holder end local function decor(parent, w, h, x, y, transparency, rotation) local img = make("ImageLabel", { Size = UDim2.new(0, w, 0, h), Position = UDim2.new(0, x, 0, y), AnchorPoint = Vector2.new(0.5, 0.5), BackgroundTransparency = 1, Image = GLOW, ImageColor3 = "glowBase", ImageTransparency = transparency, ScaleType = Enum.ScaleType.Stretch, }, parent) local grad = make("UIGradient", { Rotation = rotation, Color = ColorSequence.new(C.glowFrom, C.glowTo), }, img) gradients[#gradients + 1] = grad return img end local function centered(parent, w, h) return make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, w, 0, h), BackgroundTransparency = 1, BorderSizePixel = 0, }, parent) end local function tween(inst, time, props, style, dir) local t = TweenService:Create( inst, TweenInfo.new(time, style or Enum.EasingStyle.Quad, dir or Enum.EasingDirection.Out), props ) t:Play() return t end local function ring(parent, size, thickness, color, transparency) local f = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, size, 0, size), BackgroundTransparency = 1, BorderSizePixel = 0, }, parent) make("UICorner", { CornerRadius = UDim.new(1, 0) }, f) local stroke = make("UIStroke", { Thickness = thickness, Color = color, Transparency = transparency }, f) return f, stroke end local function comet(stroke) make("UIGradient", { Transparency = NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(0.35, 0), NumberSequenceKeypoint.new(0.7, 1), NumberSequenceKeypoint.new(1, 1), }), }, stroke) end local function prep(container) local items = {} local function add(inst) if inst:IsA("GuiObject") then items[#items + 1] = { inst, "BackgroundTransparency", inst.BackgroundTransparency } if inst:IsA("TextLabel") or inst:IsA("TextButton") or inst:IsA("TextBox") then items[#items + 1] = { inst, "TextTransparency", inst.TextTransparency } elseif inst:IsA("ImageLabel") or inst:IsA("ImageButton") then items[#items + 1] = { inst, "ImageTransparency", inst.ImageTransparency } elseif inst:IsA("ScrollingFrame") then items[#items + 1] = { inst, "ScrollBarImageTransparency", inst.ScrollBarImageTransparency } end elseif inst:IsA("UIStroke") then items[#items + 1] = { inst, "Transparency", inst.Transparency } end end add(container) for _, d in ipairs(container:GetDescendants()) do add(d) end return items end local function fade(items, alpha, time) for _, it in ipairs(items) do local inst, prop, orig = it[1], it[2], it[3] local target = 1 - (1 - orig) * alpha if time and time > 0 then tween(inst, time, { [prop] = target }) else inst[prop] = target end end end local function tintTo(inst, color) if settings.tintIcons then tween(inst, 0.15, { ImageColor3 = color }) end end local function applyTheme(name, time) local theme = THEMES[name] if not theme then return end local oldFrom, oldTo = C.glowFrom, C.glowTo loadTheme(theme) local style, dir = Enum.EasingStyle.Sine, Enum.EasingDirection.InOut for i = #bindings, 1, -1 do local b = bindings[i] local inst = b[1] if inst.Parent == nil then table.remove(bindings, i) else tween(inst, time, { [b[2]] = C[b[3]] }, style, dir) end end local newFrom, newTo = C.glowFrom, C.glowTo local driver = Instance.new("NumberValue") local conn = driver.Changed:Connect(function(a) local seq = ColorSequence.new(oldFrom:Lerp(newFrom, a), oldTo:Lerp(newTo, a)) for _, g in ipairs(gradients) do g.Color = seq end end) local t = tween(driver, time, { Value = 1 }, style, dir) t.Completed:Connect(function() conn:Disconnect() driver:Destroy() for _, g in ipairs(gradients) do g.Color = ColorSequence.new(newFrom, newTo) end end) end local UI = {} UI.Jnkie = Jnkie -- Get key button customisation (KeySystem:SetGetkeyTitle / :SetGetkeyIcon). -- Stored here so it works before or after KeySystem.new, and updates a UI that is already open. local getkeySettings = { title = nil, icon = nil } local getkeyAppliers = {} local function applyGetkeyAll() for _, apply in ipairs(getkeyAppliers) do apply() end end -- Get key dropdown (KeySystem:GetMethod). Each call adds one option: -- Ophyn:GetMethod({ Title = "...", Icon = "rbxassetid://...", URL = "..." }) -- or, for a dynamic link (matches a custom service's GetKeyLink(ctx)): -- Ophyn:GetMethod({ Title = "...", Icon = "...", GetKeyLink = function(ctx) return url end }) -- Once 2+ methods are registered, the get key button grows an arrow that opens a dropdown -- to pick between them; picking one only changes the button's text/icon (SetGetkeyTitle -- keeps working as the fallback label when no method is selected yet). local getMethods = {} local selectedMethodIndex = nil function UI.GetMethod(entry) entry = entry or {} local method = { title = entry.Title ~= nil and tostring(entry.Title) or nil, icon = entry.Icon, url = entry.URL, getKeyLink = entry.GetKeyLink or entry.getKeyLink, fields = entry, -- extra custom fields, passed back as ctx to GetKeyLink } table.insert(getMethods, method) if not selectedMethodIndex then selectedMethodIndex = 1 end applyGetkeyAll() return #getMethods end -- Readable icon/text color on top of a filled color local function contrastOn(color) local luminance = 0.299 * color.R + 0.587 * color.G + 0.114 * color.B return luminance > 0.55 and Color3.fromRGB(11, 11, 11) or Color3.fromRGB(255, 255, 255) end -- Notification style (NotifStyle / KeySystem:SetNotifStyle). Read every time a notification is shown. local notifSettings = { style = nil } function UI.SetNotifStyle(style) notifSettings.style = style ~= nil and tostring(style) or nil end -- Tabs style (TabsStyle / KeySystem:SetTabsStyle): "1" Tabs in a column on the left (default), -- "2" Tabs in a row right under the topbar. Works before or after KeySystem.new: windows that -- already exist re-layout themselves through the appliers they registered. local tabsSettings = { style = nil } local tabsAppliers = {} function UI.SetTabsStyle(style) tabsSettings.style = style ~= nil and tostring(style) or nil for i = #tabsAppliers, 1, -1 do if tabsAppliers[i]() == false then table.remove(tabsAppliers, i) end end end function UI.SetUIFont(font) fontSettings.ui = resolveFont(font) applyFontAll() end function UI.SetTitleFont(font) fontSettings.title = resolveFont(font) applyFontAll() end function UI.SetGetkeyTitle(title) getkeySettings.title = title ~= nil and tostring(title) or nil applyGetkeyAll() end function UI.SetGetkeyIcon(icon) getkeySettings.icon = icon applyGetkeyAll() end function UI.new(options) local cfg = {} for k, v in pairs(Variables) do cfg[k] = v end for k, v in pairs(options or {}) do cfg[k] = v end local HUB_NAME = tostring(cfg.Title) local HUB_SUBTITLE = tostring(cfg.Description) local FOLDER = cfg.Folder local LOGO = assetId(cfg.Logo) or Images.LOGO -- Preloads every icon (+ the logo) as early as possible. The Key System content -- only becomes visible/interactive once this finishes (see `iconsPreloaded` -- below), so icons and images are guaranteed to be loaded before the Key -- System is shown to the user. local iconsPreloaded = false task.spawn(function() pcall(function() local list = {} for _, id in pairs(Images) do if type(id) == "string" then table.insert(list, id) end end table.insert(list, LOGO) game:GetService("ContentProvider"):PreloadAsync(list) end) iconsPreloaded = true end) local INTRO_SIZE = tonumber(cfg.startintro_size) or 80 local LOADING_TIME = 3 -- fixed: icons/images preload during this time local SQUARE_TIME = tonumber(cfg.squareintro_time) or 1.2 local SHOW_SQUARE_CONTORN = asBool(cfg.squarecontorn, true) settings.tintLogo = asBool(cfg.Changelogocolor, true) settings.tintIcons = asBool(cfg.Changeiconscolor, true) local SHOW_GETKEY = asBool(cfg.getkey, true) local SHOW_CHANGE_THEME = asBool(cfg.ChangeTheme, true) local function parseHex(c, def) if typeof and typeof(c) == "Color3" then return c end if type(c) == "string" and c:sub(1,1) == "#" and #c == 7 then local r = tonumber(c:sub(2,3), 16) or 255 local g = tonumber(c:sub(4,5), 16) or 255 local b = tonumber(c:sub(6,7), 16) or 255 return Color3.fromRGB(r, g, b) end return def end local themeName = type(cfg.Theme) == "string" and cfg.Theme or "Plant-Dark" if not THEMES[themeName] then for k, _ in pairs(THEMES) do if string.lower(k) == string.lower(tostring(themeName)) then themeName = k break end end end if not THEMES[themeName] then themeName = "Plant-Dark" end themeIndex = table.find(THEME_ORDER, themeName) or 1 loadTheme(THEMES[themeName]) local customTheme = (type(cfg.ThemeConfig) == "table" and cfg.ThemeConfig) or (type(cfg.CustomTheme) == "table" and cfg.CustomTheme) or (type(cfg.Theme) == "table" and cfg.Theme) if customTheme and type(customTheme) == "table" then local function getVal(...) for _, k in ipairs({...}) do if customTheme[k] ~= nil then return customTheme[k] end end return nil end local acc = getVal("accent", "Accent", "primary", "Primary") local bg = getVal("bg", "Background", "Bg") local card = getVal("card", "Card", "surface", "Surface") local stroke = getVal("stroke", "Stroke", "border", "Border") local text = getVal("text", "Text", "textColor", "TextColor") local muted = getVal("muted", "Muted") local submitBg = getVal("submitBg", "Submit", "submit", "SubmitBg") local submitText = getVal("submitText", "SubmitText") if acc then local cAcc = parseHex(acc, C.accent) C.accent = cAcc C.glowBase = cAcc C.glowFrom = cAcc if not submitBg then C.submitBg = cAcc end end if bg then C.bg = parseHex(bg, C.bg) end if card then C.card = parseHex(card, C.card) end if stroke then C.stroke = parseHex(stroke, C.stroke) end if text then C.text = parseHex(text, C.text) end if muted then C.muted = parseHex(muted, C.muted) end if submitBg then C.submitBg = parseHex(submitBg, C.submitBg) end if submitText then C.submitText = parseHex(submitText, C.submitText) end end local DISCORD_LINK = tostring(cfg.discord_link or "") local WEBSITE_LINK = tostring(cfg.website_link or "") local HAS_DISCORD = DISCORD_LINK ~= "" local HAS_WEBSITE = WEBSITE_LINK ~= "" -- card = whether each card shows up at all, separate from whether a link is set. -- Discord and Information default to shown; Website defaults to whatever HAS_WEBSITE -- is (most people don't have one, so it stays hidden unless a link is actually given). -- What the person passes to KeySystem.new wins over the defaults in variables.lua. -- Accepts Discord/Website (or lowercase) as true/false or "true"/"false". local function cardFlag(default, ...) for _, source in ipairs({ options or {}, Variables }) do for _, key in ipairs({ ... }) do if source[key] ~= nil then return asBool(source[key], default) end end end return default end local SHOW_DISCORD_CARD = cardFlag(true, "Discord", "discord") local SHOW_WEBSITE_CARD = cardFlag(HAS_WEBSITE, "Website", "website") local SHOW_INFO_CARD = cardFlag(true, "Informations", "Information", "informations", "information") -- Only Discord enabled (no Website card): it starts expanded to fill the free space local SHOW_INTRO = cardFlag(true, "Intro", "intro") -- Keyless mode: Keyless = { disabletextbox, disablegetkey, showcard, autoconfirm }. -- Passing the table turns it on (enabled = false keeps it off); Keyless = true/false also works. -- What the person passes to KeySystem.new wins over variables.lua. local KL = { disabletextbox = true, disablegetkey = true, showcard = true, autoconfirm = false } local KEYLESS = false do local raw for _, source in ipairs({ options or {}, Variables }) do local v = source.Keyless if v == nil then v = source.keyless end if v ~= nil then raw = v break end end if type(raw) == "table" then KEYLESS = asBool(raw.enabled, true) for k, default in pairs(KL) do KL[k] = asBool(raw[k], default) end elseif raw ~= nil then KEYLESS = asBool(raw, false) end end local SHOW_KEYLESS_CARD = KEYLESS and KL.showcard -- With the Keyless card on, Discord starts collapsed so both cards fit local DISCORD_STARTS_OPEN = SHOW_DISCORD_CARD and not SHOW_WEBSITE_CARD and HAS_DISCORD and not SHOW_KEYLESS_CARD -- Notification style: "1" Stripe, "2" Pill, "3" Island, "4" Ring, "5" Solid local NOTIF_STYLE = "1" for _, source in ipairs({ options or {}, Variables }) do local value = source.NotifStyle if value == nil then value = source.notifstyle end if value ~= nil then NOTIF_STYLE = tostring(value) break end end local INVITE_DISPLAY, INVITE_URL, INVITE_CODE = "Not Configured", "", "" if HAS_DISCORD then local invite = DISCORD_LINK if not invite:find("[/.]") then invite = "discord.gg/" .. invite end INVITE_DISPLAY = invite:gsub("^https?://", "") INVITE_URL = invite:match("^https?://") and invite or ("https://" .. invite) INVITE_CODE = (INVITE_DISPLAY:gsub("[?#].*$", "")):match("([^/]+)/*$") or INVITE_DISPLAY end local WEBSITE_DISPLAY, WEBSITE_URL = "Not Configured", "" if HAS_WEBSITE then WEBSITE_DISPLAY = WEBSITE_LINK:gsub("^https?://", "") WEBSITE_URL = WEBSITE_LINK:match("^https?://") and WEBSITE_LINK or ("https://" .. WEBSITE_LINK) end -- KeySystem = { Key = {"1234", "5678"} or function(key) -> valid, reason, URL = "...", SaveKey = false, -- API = { { Type = "platoboost" | "panda" | "jnkie", ... } } } local KEY_CFG = (type(cfg.KeySystem) == "table" and not cfg.KeySystem.__isUnoAuthInstance and not cfg.KeySystem.__isJnkieInstance and not cfg.KeySystem.__isUnoAuth and not cfg.KeySystem.__isJnkie and cfg.KeySystem) or {} local KEY_LIST = KEY_CFG.Key if KEY_LIST == nil then KEY_LIST = cfg.Key or cfg.key or cfg.KEY_LIST or cfg.KeyList or cfg.keyList or (KEY_CFG ~= cfg.KeySystem and cfg.KeySystem) or nil end -- Key services (KeySystem.API). Each entry is built by its Type. local SERVICE_BUILDERS = { platoboost = function(entry) return Platoboost.new(entry) end, -- { Type = "panda", ServiceId = "..." } panda = function(entry) return Panda.new(entry) end, -- { Type = "jnkie", Service = "...", Identifier = "...", Provider = "Mixed" } jnkie = function(entry) local instance = Jnkie.new(entry) return { CheckKey = function(_, key) local result = instance:CheckKey(key) local reason = result and (result.error or result.message) return result ~= nil and result.valid == true, reason end, GetKeyLink = function() return instance:GetKeyLink() end, } end, } -- Your own service: -- { Type = "custom", ServiceId = 1234, --[[ any fields you want ]] -- CheckKey = function(key, ctx) return valid, reason end, -- required -- GetKeyLink = function(ctx) return url end } -- optional ("Get a key" button) -- ctx = every field of the entry (ServiceId, Secret, ...) + ctx.Request -- (the executor's HTTP function, or nil). GetKeyLink can return nil, "reason" on failure. local function customRequestFunction() return request or http_request or (syn and syn.request) or (http and http.request) end SERVICE_BUILDERS.custom = function(entry) local checker = entry.CheckKey or entry.checkKey if type(checker) ~= "function" then error("KeySystem.API custom entry needs a CheckKey function") end local getLink = entry.GetKeyLink or entry.getKeyLink -- Built on every call, so the person's own fields can override Request. local function context() local ctx = { Request = customRequestFunction() } for k, v in pairs(entry) do ctx[k] = v end return ctx end return { CheckKey = function(_, key) local valid, why = checker(key, context()) return valid == true, why end, GetKeyLink = (type(getLink) == "function") and function() return getLink(context()) end or nil, } end SERVICE_BUILDERS.pandaauth = SERVICE_BUILDERS.panda -- alias local apiEntries = type(KEY_CFG.API) == "table" and KEY_CFG.API or {} if apiEntries.Type ~= nil or apiEntries.type ~= nil then apiEntries = { apiEntries } -- a single entry without the outer list end local API_SERVICES = {} for i, entry in ipairs(apiEntries) do local kind = type(entry) == "table" and tostring(entry.Type or entry.type or ""):lower() or "" local builder = SERVICE_BUILDERS[kind] if builder then local ok, instance = pcall(builder, entry) if ok and instance then table.insert(API_SERVICES, instance) else warn("[" .. HUB_NAME .. "] KeySystem.API[" .. i .. "] failed to load: " .. tostring(instance)) end else warn("[" .. HUB_NAME .. "] KeySystem.API[" .. i .. "] has an unknown Type: '" .. kind .. "'") end end if KEY_LIST == nil and #API_SERVICES == 0 then KEY_LIST = { "key" } end local KEY_URL = tostring(KEY_CFG.URL or cfg.getkey_link or cfg.GetKeyUrl or cfg.getKeyUrl or cfg.URL or "") local KEY_SAVE = asBool(KEY_CFG.SaveKey ~= nil and KEY_CFG.SaveKey or cfg.SaveKey, false) -- Links usados pelos botões (Get a key / Discord / Website) local LINKS = { getKey = KEY_URL, website = WEBSITE_URL, discord = INVITE_URL, } local function isCallable(v) if type(v) == "function" then return true end local mt = type(v) == "table" and getmetatable(v) return mt ~= nil and mt.__call ~= nil end -- Auto-detect a Jnkie.Validator() adapter so "Get a key" can call -- Jnkie:GetKeyLink() on its own, with no KeySystem.URL required. -- Also accepts a *raw* Jnkie instance (Key = jnkie instead of -- Key = jnkie:Validator()) and upgrades it automatically. if type(KEY_LIST) == "table" and KEY_LIST.__isJnkieInstance and not KEY_LIST.__isJnkie then KEY_LIST = KEY_LIST:Validator() end if type(KEY_LIST) == "table" and KEY_LIST.__isUnoAuthInstance and not KEY_LIST.__isUnoAuth then KEY_LIST = KEY_LIST:Validator() end local KEY_JNKIE = type(KEY_LIST) == "table" and KEY_LIST.__isJnkie and KEY_LIST.__instance or nil local KEY_UNOAUTH = type(KEY_LIST) == "table" and KEY_LIST.__isUnoAuth and KEY_LIST.__instance or nil -- Retorna valid (boolean) e reason (string quando inválida). -- Erros aqui são pegos pelo pcall do runKeyCheck ("Something went wrong"). local function validateKey(key) local reason -- Key = { "a", "b" } | "a" | function(key) | Jnkie:Validator() if KEY_LIST ~= nil then if isCallable(KEY_LIST) then local valid, why = KEY_LIST(key) if valid then return true end reason = why elseif type(KEY_LIST) == "table" then for _, k in ipairs(KEY_LIST) do if tostring(k) == key then return true end end elseif tostring(KEY_LIST) == key then return true end end -- KeySystem.API (Platoboost / Panda / Jnkie) for _, service in ipairs(API_SERVICES) do local ok, valid, why = pcall(service.CheckKey, service, key) if ok and valid then return true end reason = (ok and why) or (not ok and tostring(valid)) or reason end return false, reason end local function safeIsFile(path) if not isfile then return false end local ok, res = pcall(isfile, path) return ok and res == true end local function safeReadFile(path) if not readfile then return nil end local ok, res = pcall(readfile, path) if ok and type(res) == "string" then return res end return nil end local function safeWriteFile(path, contents) if not writefile then return false end if FOLDER and FOLDER ~= "" and isfolder and makefolder then local ok, exists = pcall(isfolder, FOLDER) if ok and not exists then pcall(makefolder, FOLDER) end end return pcall(writefile, path, contents) == true end -- Nome do arquivo da key = hash gerada (determinística: mesmo Folder + Title = mesmo arquivo) local function hashName(seed) local bxor = bit32 and bit32.bxor local parts = {} for round = 1, 4 do local h = (2166136261 + round * 16777619) % 4294967296 local input = seed .. "|" .. round for i = 1, #input do local b = input:byte(i) h = bxor and bxor(h, b) or ((h + b) % 4294967296) h = (h * 16777619) % 4294967296 end parts[round] = string.format("%08x", h) end return table.concat(parts) end local KEY_HASH = hashName(tostring(FOLDER or "") .. "|" .. HUB_NAME) local KEY_FILE = (FOLDER and FOLDER ~= "" and (FOLDER .. "/" .. (cfg.SaveFile or cfg.savefile or KEY_HASH))) or (cfg.SaveFile or cfg.savefile or KEY_HASH) local SAVED_KEY = nil if KEY_SAVE and safeIsFile(KEY_FILE) then local contents = safeReadFile(KEY_FILE) if contents then contents = contents:match("^%s*(.-)%s*$") if contents ~= "" then SAVED_KEY = contents end end end -- Information card stats: how many key checks were valid, how many came back -- expired, and when a key last passed. Stored locally per Folder + Title, same -- as the saved key, just under a different hashed file name. local STATS_HASH = hashName(tostring(FOLDER or "") .. "|" .. HUB_NAME .. "|stats") local STATS_FILE = (FOLDER and FOLDER ~= "" and (FOLDER .. "/" .. STATS_HASH)) or STATS_HASH local STATS = { valid = 0, expired = 0, last = 0 } do local contents = safeReadFile(STATS_FILE) if contents then local ok, data = pcall(function() return HttpService:JSONDecode(contents) end) if ok and type(data) == "table" then STATS.valid = tonumber(data.valid) or 0 STATS.expired = tonumber(data.expired) or 0 STATS.last = tonumber(data.last) or 0 end end end local function saveStats() local ok, encoded = pcall(function() return HttpService:JSONEncode(STATS) end) if ok then safeWriteFile(STATS_FILE, encoded) end end local function formatAgo(ts) if not ts or ts <= 0 then return "Never" end local diff = os.time() - ts if diff < 60 then return "Just now" elseif diff < 3600 then return math.floor(diff / 60) .. " min ago" elseif diff < 86400 then return math.floor(diff / 3600) .. " h ago" else return math.floor(diff / 86400) .. " d ago" end end local state = { ready = false, closing = false } local snapLocked = false local root = Instance.new("ScreenGui") root.Name = "ophyn-ui-wow" root.Enabled = true root.DisplayOrder = 999 root.IgnoreGuiInset = true root.ResetOnSpawn = false root.ZIndexBehavior = Enum.ZIndexBehavior.Sibling root.ClipToDeviceSafeArea = true local main = make("Frame", { Name = "Frame", Size = UDim2.new(0, INTRO_SIZE, 0, INTRO_SIZE), Position = UDim2.new(0.5, 0, 0.5, 0), AnchorPoint = Vector2.new(0.5, 0.5), BackgroundTransparency = 1, BorderSizePixel = 0, }, root) local shadow = make("ImageLabel", { Size = UDim2.new(1, 50, 1, 50), Position = UDim2.new(0, -25, 0, -25), BackgroundTransparency = 1, Image = Images.SHADOW, ImageColor3 = Color3.fromRGB(0, 0, 0), ImageTransparency = 1, ScaleType = Enum.ScaleType.Slice, SliceCenter = Rect.new(49, 49, 450, 450), }, main) local canvas = make("Frame", { Size = UDim2.new(1, 0, 1, 0), BackgroundColor3 = "bg", BackgroundTransparency = 1, BorderSizePixel = 0, ClipsDescendants = true, }, main) local canvasCorner = make("UICorner", { CornerRadius = UDim.new(0, 10) }, canvas) local borderStroke = make("UIStroke", { Thickness = 1, ApplyStrokeMode = Enum.ApplyStrokeMode.Border, Color = "accent", Transparency = 1, }, canvas) local decorGroup = make("CanvasGroup", { Size = UDim2.new(1, 0, 1, 0), BackgroundTransparency = 1, BorderSizePixel = 0, GroupTransparency = 1, }, canvas) make("UICorner", { CornerRadius = UDim.new(0, 10) }, decorGroup) local bgFrame = centered(decorGroup, FINAL_W, FINAL_H) decor(bgFrame, 380, 140, 230, 266, 0.86, 270) decor(bgFrame, 100, 46, -8, 252, 0.75, 90) decor(bgFrame, 400, 184, 450, 8, 0.92, 90) decor(bgFrame, 70, 138, 5, -5, 0.78, 90) local ctx = { C = C, make = make, frame = frame, text = text, round = round, tween = tween, prep = prep, fade = fade, images = Images, FONT = FONT, FONT_BOLD = FONT_BOLD, markBoldFont = markBoldFont, root = root, canvas = canvas, state = state, tintIcons = settings.tintIcons, getStyle = function() return notifSettings.style or NOTIF_STYLE end, cfg = { NOTIF_W = NOTIF_W, NOTIF_H = NOTIF_H, NOTIF_TRANSPARENCY = NOTIF_TRANSPARENCY, NOTIF_COLOR = NOTIF_COLOR, NOTIF_BLUR = NOTIF_BLUR, }, } local notifs = Notification.new(ctx) local notify = notifs.notify local Blur = notifs.blur local intro = centered(canvas, FINAL_W, FINAL_H) local introLogo = make("ImageLabel", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, 64, 0, 58), BackgroundTransparency = 1, Image = LOGO, ImageColor3 = logoRole("accent"), ImageTransparency = 1, ScaleType = Enum.ScaleType.Fit, }, intro) local spinnerHolder = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 36), Size = UDim2.new(0, 36, 0, 36), BackgroundTransparency = 1, BorderSizePixel = 0, }, intro) local ringTrack = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, 24, 0, 24), BackgroundTransparency = 1, BorderSizePixel = 0, }, spinnerHolder) make("UICorner", { CornerRadius = UDim.new(1, 0) }, ringTrack) make("UIStroke", { Thickness = 2.5, Color = "muted", Transparency = 0.75 }, ringTrack) local spinner = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, 24, 0, 24), BackgroundTransparency = 1, BorderSizePixel = 0, }, spinnerHolder) make("UICorner", { CornerRadius = UDim.new(1, 0) }, spinner) local spinnerStroke = make("UIStroke", { Thickness = 2.5, Color = "accent" }, spinner) make("UIGradient", { Transparency = NumberSequence.new({ NumberSequenceKeypoint.new(0, 0), NumberSequenceKeypoint.new(0.35, 0), NumberSequenceKeypoint.new(0.7, 1), NumberSequenceKeypoint.new(1, 1), }), }, spinnerStroke) local spin = TweenService:Create( spinner, TweenInfo.new(0.9, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, -1), { Rotation = 360 } ) local checkScreen = centered(canvas, FINAL_W, FINAL_H) checkScreen.Visible = false local ringHolder = centered(checkScreen, 64, 64) ringHolder.Position = UDim2.new(0.5, 0, 0.5, -12) local ringScale = make("UIScale", { Scale = 1 }, ringHolder) ring(ringHolder, 56, 3, "accent", 0) local P1, P2, P3 = Vector2.new(-12, 0), Vector2.new(-4, 9), Vector2.new(13, -9) local function makeBar(a, b) local d = b - a local bar = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, a.X, 0.5, a.Y), Size = UDim2.new(0, 0, 0, 3), Rotation = math.deg(math.atan2(d.Y, d.X)), BackgroundColor3 = "accent", BorderSizePixel = 0, Visible = false, }, ringHolder) make("UICorner", { CornerRadius = UDim.new(1, 0) }, bar) return { frame = bar, a = a, b = b, len = d.Magnitude } end local checkBar1 = makeBar(P1, P2) local checkBar2 = makeBar(P2, P3) local fxLayer = frame(checkScreen, 0, 0, FINAL_W, FINAL_H) fxLayer.ZIndex = 3 local checkText = text(checkScreen, "Correct Key!", 0, 156, FINAL_W, 22, 16, "text", Enum.TextXAlignment.Center) markBoldFont(checkText) checkText.TextTransparency = 1 local ringItems = prep(ringHolder) fade(ringItems, 0) local morph = centered(canvas, NOTIF_W, 62) morph.Visible = false -- "Loading Script.." card. It follows NotifStyle: the window shrinks into that notification's shape. local MORPH_TITLE, MORPH_HINT = "Loading Script..", "Can take 1-2s..." local function morphLoader(parent, size, thickness, arcColor, trackColor, trackTransparency) ring(parent, size, thickness, trackColor, trackTransparency) local arc, arcStroke = ring(parent, size, thickness, arcColor, 0) comet(arcStroke) return TweenService:Create( arc, TweenInfo.new(0.8, Enum.EasingStyle.Linear, Enum.EasingDirection.Out, -1), { Rotation = 360 } ) end local function morphLabel(x, y, w, h, str, size, color, bold) local l = text(morph, str, x, y, w, h, size, color) if bold then markBoldFont(l) end return l end local function buildMorph(key) morph:ClearAllChildren() local w, h = NOTIF_W, 62 local spec = { top = false, radius = 10, bg = C[NOTIF_COLOR], bgTransparency = NOTIF_TRANSPARENCY, border = C.stroke, borderTransparency = 0.35, } local spin if key == "2" then -- Pill w, h = 240, 36 spec.radius = 18 local box = frame(morph, 6, 6, 24, 24) spin = morphLoader(box, 20, 2, "accent", "muted", 0.75) make("TextLabel", { Position = UDim2.new(0, 38, 0, 0), Size = UDim2.new(0, w - 52, 0, h), BackgroundTransparency = 1, BorderSizePixel = 0, RichText = true, Text = "Loading script.. 1-2s", TextSize = 13, TextColor3 = "text", TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Center, FontFace = FONT, }, morph) elseif key == "3" then -- Island w, h = 260, 52 spec.top = true spec.radius = 26 spec.bg = Color3.fromRGB(0, 0, 0) spec.bgTransparency = 0.06 spec.border = Color3.fromRGB(42, 42, 48) local badge = frame(morph, 10, 10, 32, 32, "accent", 0.86) round(badge, 16, "accent") badge.UIStroke.Transparency = 0.6 spin = morphLoader(badge, 16, 2, "accent", "muted", 0.75) morphLabel(54, 9, w - 70, 16, MORPH_TITLE, 13, Color3.fromRGB(244, 244, 245), true) morphLabel(54, 27, w - 70, 14, MORPH_HINT, 12, Color3.fromRGB(154, 154, 162)) elseif key == "4" then -- Ring h = 60 local box = frame(morph, 10, 10, 40, 40) spin = morphLoader(box, 34, 3, "accent", "muted", 0.75) morphLabel(62, 11, w - 76, 18, MORPH_TITLE, 13, "text", true) morphLabel(62, 31, w - 76, 16, MORPH_HINT, 12, "muted") elseif key == "5" then -- Solid h = 58 local accent = C.accent local onColor = contrastOn(accent) spec.bg = accent spec.bgTransparency = 0.04 spec.borderTransparency = 1 local box = frame(morph, 14, (h - 22) / 2, 22, 22) spin = morphLoader(box, 20, 3, onColor, onColor, 0.75) morphLabel(48, 10, w - 62, 18, MORPH_TITLE, 13, onColor, true) morphLabel(48, 30, w - 62, 16, MORPH_HINT, 12, onColor:Lerp(accent, 0.35)) else -- Stripe round(frame(morph, 8, 10, 3, h - 20, "accent", 0), 2) morphLabel(22, 11, w - 36, 18, MORPH_TITLE, 13, "text", true) morphLabel(22, 30, w - 36, 16, MORPH_HINT, 12, "muted") local trackW = w - 44 round(frame(morph, 22, h - 9, trackW, 2, "accent", 0.8), 1) local fill = frame(morph, 22, h - 9, 0, 2, "accent", 0) round(fill, 1) spin = TweenService:Create( fill, TweenInfo.new(2.2, Enum.EasingStyle.Linear), { Size = UDim2.new(0, trackW, 0, 2) } ) end morph.Size = UDim2.new(0, w, 0, h) local items = prep(morph) fade(items, 0) spec.w, spec.h, spec.spin, spec.items = w, h, spin, items return spec end local content = centered(canvas, FINAL_W, FINAL_H) content.Visible = false local left = frame(content, 0, 0, 272, 260) make("ImageLabel", { Position = UDim2.new(0, 22, 0, 20), Size = UDim2.new(0, 36, 0, 32), BackgroundTransparency = 1, Image = LOGO, ImageColor3 = logoRole("accent"), ScaleType = Enum.ScaleType.Fit, }, left) local hubTitle = text(left, HUB_NAME, 66, 20, 190, 22, 20, "text") markTitleFont(hubTitle) hubTitle.TextTruncate = Enum.TextTruncate.AtEnd local hubSubtitle = text(left, HUB_SUBTITLE, 66, 42, 190, 14, 12, "muted") hubSubtitle.TextTruncate = Enum.TextTruncate.AtEnd local licenseLabel = text(left, "License key", 22, 78, 228, 14, 11, "muted") local inputBox = frame(left, 22, 96, 228, 36, "input", 0) inputBox.ClipsDescendants = true round(inputBox, 8, "stroke") icon(inputBox, 12, 10, "muted", Images.KEY) local KEY_MAX_LENGTH = 256 local keyBox = make("TextBox", { Name = "TextBox", Position = UDim2.new(0, 38, 0, 0), Size = UDim2.new(1, -48, 1, 0), BackgroundTransparency = 1, BorderSizePixel = 0, Text = "", TextSize = 13, TextColor3 = "text", TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, PlaceholderText = "Paste your key here", PlaceholderColor3 = "muted", ClearTextOnFocus = false, MultiLine = false, FontFace = FONT, }, inputBox) keyBox:GetPropertyChangedSignal("Text"):Connect(function() if #keyBox.Text > KEY_MAX_LENGTH then keyBox.Text = keyBox.Text:sub(1, KEY_MAX_LENGTH) end end) local submit = make("TextButton", { Name = "TextButton", Position = UDim2.new(0, 22, 0, 142), Size = UDim2.new(0, 110, 0, 34), BackgroundColor3 = "submitBg", BackgroundTransparency = 0.12, BorderSizePixel = 0, AutoButtonColor = false, Text = "Submit", TextSize = 13, TextColor3 = "submitText", FontFace = FONT, }, left) round(submit, 8) make("UIPadding", { PaddingLeft = UDim.new(0, 24) }, submit) icon(submit, -12, 9, "submitText", Images.SUBMIT) local getKey = make("TextButton", { Name = "TextButton", Position = UDim2.new(0, 140, 0, 142), Size = UDim2.new(0, 110, 0, 34), BackgroundColor3 = "btn2", BorderSizePixel = 0, AutoButtonColor = false, Text = "Get a key", TextTruncate = Enum.TextTruncate.AtEnd, TextSize = 13, TextColor3 = "text", FontFace = FONT, }, left) round(getKey, 8, "stroke") local getKeyPadding = make("UIPadding", { PaddingLeft = UDim.new(0, 24) }, getKey) local getKeyIcon = icon(getKey, -12, 9, "text", Images.KEY) -- Dropdown arrow: a separate hit area over the button's right edge, only visible -- once there are 2+ methods (see Ophyn:GetMethod above). Being its own TextButton on -- top of "getKey" means clicking it never also fires getKey's own click below. local methodArrow = make("TextButton", { Name = "TextButton", Position = UDim2.new(1, -26, 0, 0), Size = UDim2.new(0, 26, 1, 0), BackgroundTransparency = 1, AutoButtonColor = false, Text = "\226\150\190", -- U+25BE, small down-pointing triangle TextSize = 11, TextColor3 = "text", FontFace = FONT, Visible = false, }, getKey) -- Dropdown list, parented to "main" (not "canvas") so it isn't clipped by the -- window's edges when it opens above/below the button. local methodDropdown = make("Frame", { Name = "GetKeyDropdown", BackgroundColor3 = "card", BorderSizePixel = 0, Visible = false, ZIndex = 50, ClipsDescendants = true, }, main) round(methodDropdown, 8, "stroke") local function closeMethodDropdown() methodDropdown.Visible = false end local function rebuildMethodDropdown() for _, child in ipairs(methodDropdown:GetChildren()) do if child:IsA("GuiObject") then child:Destroy() end end local rowH = 32 for i, m in ipairs(getMethods) do local row = make("TextButton", { Name = "TextButton", Position = UDim2.new(0, 0, 0, (i - 1) * rowH), Size = UDim2.new(1, 0, 0, rowH), BackgroundTransparency = 1, AutoButtonColor = false, Text = "", ZIndex = 51, }, methodDropdown) icon(row, 10, 8, "text", assetId(m.icon) or Images.KEY) local label = text(row, m.title or ("Method " .. i), 34, 0, 96, rowH, 12, "text") label.ZIndex = 52 row.MouseButton1Click:Connect(function() selectedMethodIndex = i applyGetkeyAll() closeMethodDropdown() end) end methodDropdown.Size = UDim2.new(0, 140, 0, rowH * math.max(#getMethods, 1)) end methodArrow.MouseButton1Click:Connect(function() if not state.ready or state.closing or #getMethods < 2 or (KEYLESS and KL.disablegetkey) then return end if methodDropdown.Visible then closeMethodDropdown() return end rebuildMethodDropdown() local pos = getKey.AbsolutePosition - main.AbsolutePosition local h = methodDropdown.AbsoluteSize.Y methodDropdown.Position = UDim2.new(0, pos.X, 0, pos.Y - h - 6) -- opens upward methodDropdown.Visible = true end) local function applyGetkey() local method = getMethods[selectedMethodIndex or 0] local title = method and method.title local iconValue = method and method.icon if not title or title == "" then title = getkeySettings.title end getKey.Text = (title and title ~= "") and title or "Get a key" local image = getKeyIcon:FindFirstChild("iconimage") if image then Lucide.apply(image, assetId(iconValue) or assetId(getkeySettings.icon) or Images.KEY) end local showArrow = #getMethods > 1 methodArrow.Visible = showArrow getKeyPadding.PaddingRight = showArrow and UDim.new(0, 20) or UDim.new(0, 0) if not showArrow then closeMethodDropdown() end end applyGetkey() table.insert(getkeyAppliers, applyGetkey) root.Destroying:Connect(function() local index = table.find(getkeyAppliers, applyGetkey) if index then table.remove(getkeyAppliers, index) end end) if not SHOW_GETKEY then getKey.Visible = false submit.Size = UDim2.new(0, 228, 0, 34) end -- Avatar + "Welcome Back / !" local avatar = make("ImageLabel", { Position = UDim2.new(0, 22, 0, 214), Size = UDim2.new(0, 32, 0, 32), BackgroundColor3 = "input", BorderSizePixel = 0, Image = player and ("rbxthumb://type=AvatarHeadShot&id=" .. player.UserId .. "&w=150&h=150") or "", ScaleType = Enum.ScaleType.Crop, }, left) round(avatar, 16, "stroke") text(left, "Welcome Back", 62, 215, 188, 14, 11, "muted") local welcomeName = text(left, ((player and player.DisplayName) or "User") .. "!", 62, 229, 188, 16, 14, "text") markBoldFont(welcomeName) welcomeName.TextTruncate = Enum.TextTruncate.AtEnd frame(content, 272, 20, 1, 220, "stroke", 0) local right = frame(content, 273, 0, 187, 260) text(right, "Detected game", 20, 24, 147, 14, 11, "muted") local gameCard = frame(right, 20, 42, 147, 52, "card", 0) round(gameCard, 8) local gameImg = make("ImageLabel", { Position = UDim2.new(0, 9, 0, 9), Size = UDim2.new(0, 34, 0, 34), BackgroundColor3 = "input", BorderSizePixel = 0, Image = Images.GAME_PLACEHOLDER, ScaleType = Enum.ScaleType.Stretch, }, gameCard) round(gameImg, 7, "stroke") local gameName = text(gameCard, "Loading...", 52, 10, 90, 14, 12, "text") gameName.TextTruncate = Enum.TextTruncate.AtEnd local gameStatus = text(gameCard, "Checking...", 52, 27, 90, 13, 11, "muted") local rows = frame(right, 0, 0, 187, 260) text(rows, "Executor", 20, 106, 60, 14, 11, "muted") local executorLabel = text(rows, "Detecting...", 80, 106, 87, 14, 11, "text", Enum.TextXAlignment.Right) executorLabel.TextTruncate = Enum.TextTruncate.AtEnd text(rows, "Status", 20, 126, 60, 14, 11, "muted") local statusValue = text(rows, "Key required", 80, 126, 87, 14, 11, "warn", Enum.TextXAlignment.Right) local rightDivider = frame(right, 20, 148, 147, 1, "stroke", 0) -- Scrollable card list. Cards are laid out inside it (see layoutCards); once they -- no longer fit it can be scrolled with the wheel, by touch, or by dragging. -- CARD_PAD leaves room for the 1px outer card strokes, which would be clipped otherwise. local CARD_PAD = 2 local CARD_VIEW_BOTTOM = 256 -- bottom edge of the visible card area local cardScroll = make("ScrollingFrame", { Name = "Cards", Position = UDim2.new(0, 20 - CARD_PAD, 0, 158 - CARD_PAD), Size = UDim2.new(0, 147 + CARD_PAD + 5, 0, CARD_VIEW_BOTTOM - 158 + CARD_PAD), BackgroundTransparency = 1, BorderSizePixel = 0, CanvasSize = UDim2.new(0, 0, 0, 0), ScrollingDirection = Enum.ScrollingDirection.Y, ElasticBehavior = Enum.ElasticBehavior.Never, VerticalScrollBarInset = Enum.ScrollBarInset.None, ScrollBarThickness = 2, ScrollBarImageTransparency = 0.45, ClipsDescendants = true, }, right) setRole(cardScroll, "ScrollBarImageColor3", "muted") local function linkButton(y, title, subtitle, image) local btn = make("TextButton", { Name = "TextButton", Position = UDim2.new(0, 20, 0, y), Size = UDim2.new(0, 147, 0, 40), BackgroundColor3 = "card", BorderSizePixel = 0, AutoButtonColor = false, Text = "", }, cardScroll) round(btn, 8, "stroke") local iconHolder = icon(btn, 11, 12, "accent", image) local titleLabel = text(btn, title, 36, 6, 106, 14, 12, "text") local subLabel = text(btn, subtitle, 36, 21, 106, 13, 11, "muted") subLabel.TextTruncate = Enum.TextTruncate.AtEnd return btn, iconHolder, titleLabel, subLabel end local discord, discordIcon, discordTitle, discordSub = linkButton(158, "Discord", INVITE_DISPLAY, Images.DISCORD) local website = linkButton(206, "Website", WEBSITE_DISPLAY, Images.LINK) discord.Visible = SHOW_DISCORD_CARD website.Visible = SHOW_WEBSITE_CARD discordTitle.TextTruncate = Enum.TextTruncate.AtEnd discord.ClipsDescendants = true local discordExtra = frame(discord, 0, 0, 147, 82) discordExtra.Visible = false local serverIcon = make("ImageLabel", { Position = UDim2.new(0, 9, 0, 7), Size = UDim2.new(0, 26, 0, 26), BackgroundColor3 = "input", BorderSizePixel = 0, Image = LOGO, ImageColor3 = logoRole("accent"), ScaleType = Enum.ScaleType.Fit, }, discordExtra) round(serverIcon, 8, "stroke") local linkHit = make("TextButton", { Position = UDim2.new(0, 40, 0, 19), Size = UDim2.new(0, 102, 0, 17), BackgroundTransparency = 1, BorderSizePixel = 0, AutoButtonColor = false, Text = "", }, discordExtra) frame(discordExtra, 10, 41, 127, 1, "stroke", 0) local function statBlock(x, label, dotColor) local num = text(discordExtra, "...", x, 47, 62, 16, 13, "text") markBoldFont(num) local dot = frame(discordExtra, x, 66, 6, 6, dotColor, 0) make("UICorner", { CornerRadius = UDim.new(1, 0) }, dot) text(discordExtra, label, x + 10, 62, 50, 14, 10, "muted") return num end local onlineNum = statBlock(12, "Online", "success") local offlineNum = statBlock(80, "Offline", "muted") local extraItems = prep(discordExtra) local rowsItems = prep(rows) local discordIconItems = prep(discordIcon) -- Information card: local stats only (valid keys, expired keys, last used) local infoCard, infoIcon, infoTitle, infoSub = linkButton(254, "Information", "Tap to view", Images.KEY) infoCard.Visible = SHOW_INFO_CARD infoCard.ClipsDescendants = true infoTitle.TextTruncate = Enum.TextTruncate.AtEnd -- Expanded Information card: same look as the expanded Discord card local INFO_OPEN_H = 92 -- Grouped in one table: UI.new is close to Lua's limit of 200 local variables. local infoUI = {} do local extra = frame(infoCard, 0, 0, 147, INFO_OPEN_H) extra.Visible = false infoUI.extra = extra local iconBox = frame(extra, 9, 7, 26, 26, "input", 0) round(iconBox, 8, "stroke") icon(iconBox, 5, 5, "accent", Images.KEY) frame(extra, 10, 41, 127, 1, "stroke", 0) local function stat(x, label, dotColor) local num = text(extra, "0", x, 46, 62, 16, 13, "text") markBoldFont(num) local dot = frame(extra, x, 66, 6, 6, dotColor, 0) make("UICorner", { CornerRadius = UDim.new(1, 0) }, dot) text(extra, label, x + 10, 62, 50, 14, 10, "muted") return num end infoUI.valid = stat(12, "Valid", "success") infoUI.expired = stat(80, "Expired", "warn") text(extra, "Last used", 12, 77, 56, 13, 10, "muted") local lastUsed = text(extra, "Never", 66, 77, 69, 13, 11, "text", Enum.TextXAlignment.Right) lastUsed.TextTruncate = Enum.TextTruncate.AtEnd infoUI.lastUsed = lastUsed end infoUI.extraItems = prep(infoUI.extra) infoUI.iconItems = prep(infoIcon) -- Keyless Mode card: informational only (no click) local keylessCard = linkButton(206, "Keyless Mode", "No key needed", Images.KEYLESS) keylessCard.Visible = SHOW_KEYLESS_CARD local closeBtn = make("TextButton", { Name = "CloseButton", AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, -12, 0, 12), Size = UDim2.new(0, 26, 0, 26), BackgroundColor3 = "card", BackgroundTransparency = 1, BorderSizePixel = 0, AutoButtonColor = false, Text = "", ZIndex = 5, }, content) make("UICorner", { CornerRadius = UDim.new(0, 7) }, closeBtn) local closeIcon = make("ImageLabel", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, 12, 0, 12), BackgroundTransparency = 1, Image = CLOSE_ICON, ImageColor3 = iconRole("muted"), ZIndex = 6, }, closeBtn) local moonBtn = make("TextButton", { Name = "ThemeButton", AnchorPoint = Vector2.new(1, 0), Position = UDim2.new(1, -38, 0, 12), Size = UDim2.new(0, 26, 0, 26), BackgroundColor3 = "card", BackgroundTransparency = 1, BorderSizePixel = 0, AutoButtonColor = false, Text = "", ZIndex = 5, }, content) make("UICorner", { CornerRadius = UDim.new(0, 7) }, moonBtn) local moonIcon = make("ImageLabel", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, 0), Size = UDim2.new(0, 10, 0, 10), BackgroundTransparency = 1, Image = MOON_ICON, ImageColor3 = iconRole("muted"), ZIndex = 6, }, moonBtn) moonBtn.Visible = SHOW_CHANGE_THEME local closeGui -- Page 2: a down arrow at the bottom of the Key System slides it up and brings in the -- topbar + Tabs (OphynWindow({ Title, Icon }), Tab:Section, Tab:Paragraph). Kept in ctx -- so it doesn't take another local in UI.new (already close to Lua's limit). It is built -- before prep(content) on purpose, so the arrow fades in and out with the Key System. ctx.pages = Pages.new({ C = C, make = make, round = round, tween = tween, prep = prep, fade = fade, setRole = setRole, icon = icon, assetId = assetId, contrastOn = contrastOn, iconRole = iconRole, logoRole = logoRole, markTitleFont = markTitleFont, -- SetTabsStyle wins over TabsStyle from KeySystem.new({ ... }) / variables.lua getTabsStyle = function() if tabsSettings.style then return tabsSettings.style end for _, source in ipairs({ options or {}, Variables }) do local value = source.TabsStyle if value == nil then value = source.tabsstyle end if value ~= nil then return tostring(value) end end return "1" end, registerTabsStyle = function(apply) table.insert(tabsAppliers, apply) end, FONT = FONT, FONT_BOLD = FONT_BOLD, images = Images, canvas = canvas, content = content, state = state, width = FINAL_W, height = FINAL_H, title = HUB_NAME, logo = LOGO, onOpen = function() closeMethodDropdown() end, requestClose = function() if not state.ready or state.closing then return end task.spawn(closeGui) end, }) -- Keyless mode: dim + lock the disabled parts. This runs BEFORE prep(content) on -- purpose, so the dimmed transparencies become the "original" values that -- fade() restores (a later fade-in would otherwise undo the dimming). if KEYLESS then local DIM = 0.5 local function dim(container) local function apply(inst) if inst:IsA("GuiObject") then inst.BackgroundTransparency = 1 - (1 - inst.BackgroundTransparency) * DIM if inst:IsA("TextLabel") or inst:IsA("TextButton") or inst:IsA("TextBox") then inst.TextTransparency = 1 - (1 - inst.TextTransparency) * DIM elseif inst:IsA("ImageLabel") or inst:IsA("ImageButton") then inst.ImageTransparency = 1 - (1 - inst.ImageTransparency) * DIM end elseif inst:IsA("UIStroke") then inst.Transparency = 1 - (1 - inst.Transparency) * DIM end end apply(container) for _, d in ipairs(container:GetDescendants()) do apply(d) end end if KL.disabletextbox then dim(licenseLabel) dim(inputBox) pcall(function() keyBox.TextEditable = false keyBox.Active = false keyBox.Interactable = false end) keyBox.Focused:Connect(function() keyBox:ReleaseFocus() end) end if KL.disablegetkey then dim(getKey) pcall(function() getKey.Active = false getKey.Interactable = false methodArrow.Active = false methodArrow.Interactable = false end) end statusValue.Text = "Keyless" setRole(statusValue, "TextColor3", "accent") end local spinnerItems = prep(spinnerHolder) local contentItems = prep(content) fade(spinnerItems, 0) fade(contentItems, 0) local SUPPORTED_GAMES = {} -- [PlaceId] = true -- SupportedGames: { [PlaceId] = true, ... } or a plain list { PlaceId, PlaceId, ... }. -- What the person passes to KeySystem.new wins over the default in variables.lua. for _, source in ipairs({ options or {}, Variables }) do local value = source.SupportedGames if value == nil then value = source.supportedgames end if type(value) == "table" then for k, v in pairs(value) do if type(v) == "number" then SUPPORTED_GAMES[v] = true elseif v then SUPPORTED_GAMES[tonumber(k) or k] = true end end break end end task.spawn(function() local ok, info = pcall(function() return MarketplaceService:GetProductInfo(game.PlaceId) end) if state.closing then return end gameName.Text = (ok and type(info) == "table" and info.Name) or "Unknown game" if game.GameId ~= 0 then gameImg.Image = "rbxthumb://type=GameIcon&id=" .. game.GameId .. "&w=150&h=150" end if SUPPORTED_GAMES[game.PlaceId] then gameStatus.Text = "Supported" setRole(gameStatus, "TextColor3", "success") else gameStatus.Text = "Not in our list" setRole(gameStatus, "TextColor3", "muted") end end) local function detectExecutor() local ok, name = pcall(function() if identifyexecutor then return identifyexecutor() elseif getexecutorname then return getexecutorname() end end) if ok and name and tostring(name) ~= "" then return tostring(name) end return "Unknown" end executorLabel.Text = detectExecutor() local function copyLink(url, label, iconKey) if not state.ready or state.closing then return false end local fn = setclipboard or toclipboard local ok = fn and pcall(fn, url) if ok then notify(label .. " copied", "The link is in your clipboard.", "success", iconKey) return true end notify("Couldn't copy", url, "warn", iconKey, 5) return false end local fetchingKeyLink = false getKey.MouseButton1Click:Connect(function() if not state.ready or state.closing then return end if KEYLESS and KL.disablegetkey then return end if #getMethods > 0 then local method = getMethods[selectedMethodIndex or 1] if not method then return end if method.url and method.url ~= "" then copyLink(method.url, "Key link", "link") return end if type(method.getKeyLink) == "function" then if fetchingKeyLink then return end fetchingKeyLink = true task.spawn(function() local req = request or http_request or (syn and syn.request) or (http and http.request) local ctx = { Request = req } for k, v in pairs(method.fields or {}) do ctx[k] = v end local ok, link, err = pcall(method.getKeyLink, ctx) fetchingKeyLink = false if not state.ready or state.closing then return end if ok and link then copyLink(link, "Key link", "link") else notify("Couldn't get a key", tostring((not ok) and link or err or "Try again."), "warn", "link", 5) end end) end return end if LINKS.getKey ~= "" then copyLink(LINKS.getKey, "Key link", "link") return end -- Services that can generate a key link (KeySystem.API and Jnkie) local linkProviders = {} for _, service in ipairs(API_SERVICES) do if service.GetKeyLink then table.insert(linkProviders, function() return service:GetKeyLink() end) end end if KEY_JNKIE then table.insert(linkProviders, function() return KEY_JNKIE:GetKeyLink() end) end if KEY_UNOAUTH and KEY_UNOAUTH.GetKeyLink then table.insert(linkProviders, function() return KEY_UNOAUTH:GetKeyLink() end) end if #linkProviders > 0 then if fetchingKeyLink then return end fetchingKeyLink = true task.spawn(function() local link, err for _, getLink in ipairs(linkProviders) do local ok, res, res2 = pcall(getLink) if ok and res then link = res break end err = ok and res2 or (not ok and res) or err end fetchingKeyLink = false if not state.ready or state.closing then return end if link then copyLink(link, "Key link", "link") elseif err == "RATE_LIMITED" then notify("Slow down", "Wait 5 minutes before requesting another link.", "warn", "link", 5) else notify("Couldn't get a link", tostring(err or "Unknown error"), "warn", "link", 5) end end) return end if LINKS.website ~= "" then copyLink(LINKS.website, "Key link", "link") return end notify("No link set", "The key link isn't set.", "warn", "link") end) local httpRequest = request or http_request or (syn and syn.request) or (http and http.request) local discordInfo = { fetching = false, ok = false, iconLoaded = false, last = 0, online = 0, offline = 0 } local discordOpen = false local infoOpen = false local function anyCardOpen() return discordOpen or infoOpen end local function refreshDiscordTitle() local target = (discordOpen and discordInfo.name) or "Discord" if discordTitle.Text == target then return end if not state.ready then discordTitle.Text = target return end tween(discordTitle, 0.12, { TextTransparency = 1 }) task.delay(0.12, function() if state.closing then return end discordTitle.Text = (discordOpen and discordInfo.name) or "Discord" tween(discordTitle, 0.15, { TextTransparency = 0 }) end) end local function formatNumber(n) local reversed = tostring(math.floor(n)):reverse():gsub("(%d%d%d)", "%1,"):reverse() return (reversed:gsub("^,", "")) end local function applyDiscordInfo() if discordInfo.ok then onlineNum.Text = formatNumber(discordInfo.online) offlineNum.Text = formatNumber(discordInfo.offline) elseif discordInfo.fetching then onlineNum.Text = "..." offlineNum.Text = "..." else onlineNum.Text = "N/A" offlineNum.Text = "N/A" end end local function fetchDiscord() if discordInfo.fetching then return end discordInfo.fetching = true applyDiscordInfo() if httpRequest then local ok, res = pcall(httpRequest, { Url = "https://discord.com/api/v10/invites/" .. INVITE_CODE .. "?with_counts=true", Method = "GET", }) if ok and res and res.StatusCode == 200 and res.Body then local okJson, data = pcall(function() return HttpService:JSONDecode(res.Body) end) if okJson and type(data) == "table" and data.approximate_member_count then local online = data.approximate_presence_count or 0 discordInfo.online = online discordInfo.offline = math.max(data.approximate_member_count - online, 0) discordInfo.ok = true discordInfo.last = os.clock() if type(data.guild) == "table" and data.guild.name then discordInfo.name = data.guild.name end local guild = data.guild local getAsset = getcustomasset or getsynasset if guild and guild.icon and not discordInfo.iconLoaded and writefile and getAsset then local url = ("https://cdn.discordapp.com/icons/%s/%s.png?size=128"):format(guild.id, guild.icon) local okI, resI = pcall(httpRequest, { Url = url, Method = "GET" }) if okI and resI and resI.StatusCode == 200 and resI.Body and #resI.Body > 0 then local okW, asset = pcall(function() local fileName = "discord_" .. INVITE_CODE .. ".png" if FOLDER and FOLDER ~= "" then if isfolder and makefolder and not isfolder(FOLDER) then makefolder(FOLDER) end fileName = FOLDER .. "/" .. fileName end writefile(fileName, resI.Body) return getAsset(fileName) end) if okW and asset then serverIcon.Image = asset unbind(serverIcon, "ImageColor3") serverIcon.ImageColor3 = Color3.fromRGB(255, 255, 255) serverIcon.ScaleType = Enum.ScaleType.Crop discordInfo.iconLoaded = true end end end end end end discordInfo.fetching = false applyDiscordInfo() refreshDiscordTitle() end if HAS_DISCORD then task.spawn(fetchDiscord) end -- Stacks whichever cards are enabled (Discord, Keyless, Website, Information, in -- that order) inside the scroll frame. Expanding a card (Discord / Information) -- pushes the cards below it down and moves the whole list up, hiding the -- Executor / Status rows. Anything that doesn't fit becomes scrollable. local CARD_GAP = 8 local cardOrder = {} if SHOW_DISCORD_CARD then table.insert(cardOrder, discord) end if SHOW_KEYLESS_CARD then table.insert(cardOrder, keylessCard) end if SHOW_WEBSITE_CARD then table.insert(cardOrder, website) end if SHOW_INFO_CARD then table.insert(cardOrder, infoCard) end local function cardHeight(card) if card == discord and discordOpen then return 82 end if card == infoCard and infoOpen then return INFO_OPEN_H end return 40 end local layoutToken = 0 -- focusCard: scrolled into view when the layout changes (used when a card expands) local function layoutCards(instant, focusCard) local Quint = Enum.EasingStyle.Quint local open = anyCardOpen() local divider = open and 106 or 148 local top = open and 114 or 158 local y = CARD_PAD local focusTop, focusBottom for _, card in ipairs(cardOrder) do local h = cardHeight(card) if card == focusCard then focusTop, focusBottom = y - CARD_PAD, y + h + CARD_PAD end if instant then card.Position = UDim2.new(0, CARD_PAD, 0, y) card.Size = UDim2.new(0, 147, 0, h) else tween(card, 0.55, { Position = UDim2.new(0, CARD_PAD, 0, y), Size = UDim2.new(0, 147, 0, h), }, Quint) end y = y + h + CARD_GAP end local canvasH = math.max(y - CARD_GAP + CARD_PAD, 0) local viewH = CARD_VIEW_BOTTOM - top + CARD_PAD local maxPos = math.max(canvasH - viewH, 0) local pos = cardScroll.CanvasPosition.Y local targetPos = math.clamp(pos, 0, maxPos) if focusTop then if focusBottom > targetPos + viewH then targetPos = focusBottom - viewH end if focusTop < targetPos then targetPos = focusTop end targetPos = math.clamp(targetPos, 0, maxPos) end local scrollPos = UDim2.new(0, 20 - CARD_PAD, 0, top - CARD_PAD) local scrollSize = UDim2.new(0, 147 + CARD_PAD + 5, 0, viewH) local canvasSize = UDim2.new(0, 0, 0, canvasH) layoutToken += 1 local token = layoutToken if instant then rightDivider.Position = UDim2.new(0, 20, 0, divider) cardScroll.Position = scrollPos cardScroll.Size = scrollSize cardScroll.CanvasSize = canvasSize cardScroll.CanvasPosition = Vector2.new(0, targetPos) return end tween(rightDivider, 0.55, { Position = UDim2.new(0, 20, 0, divider) }, Quint) -- Grow the canvas right away (so the scroll target is reachable); shrink it only -- once the cards finished moving (so the position doesn't get clamped mid-tween). if canvasH >= cardScroll.CanvasSize.Y.Offset then cardScroll.CanvasSize = canvasSize else task.delay(0.58, function() if token == layoutToken then cardScroll.CanvasSize = canvasSize end end) end tween(cardScroll, 0.55, { Position = scrollPos, Size = scrollSize, CanvasPosition = Vector2.new(0, targetPos), }, Quint) end layoutCards(true) -- Dragging the card list with the mouse (the wheel and touch scroll natively). -- A drag never counts as a click on the card under the cursor. local suppressClick = false do local dragging, dragStartY, dragStartCanvas = false, 0, 0 local function onPress(input) if input.UserInputType ~= Enum.UserInputType.MouseButton1 or dragging or not state.ready then return end if cardScroll.CanvasSize.Y.Offset <= cardScroll.AbsoluteSize.Y then return end dragging = true dragStartY = input.Position.Y dragStartCanvas = cardScroll.CanvasPosition.Y end cardScroll.InputBegan:Connect(onPress) for _, card in ipairs(cardOrder) do card.InputBegan:Connect(onPress) end local dragMove = UserInputService.InputChanged:Connect(function(input) if not dragging or input.UserInputType ~= Enum.UserInputType.MouseMovement then return end local delta = input.Position.Y - dragStartY if not suppressClick and math.abs(delta) < 5 then return end suppressClick = true local maxPos = math.max(cardScroll.CanvasSize.Y.Offset - cardScroll.AbsoluteSize.Y, 0) cardScroll.CanvasPosition = Vector2.new(0, math.clamp(dragStartCanvas - delta, 0, maxPos)) end) local dragEnd = UserInputService.InputEnded:Connect(function(input) if input.UserInputType ~= Enum.UserInputType.MouseButton1 or not dragging then return end dragging = false task.delay(0.1, function() suppressClick = false end) end) root.Destroying:Connect(function() dragMove:Disconnect() dragEnd:Disconnect() end) end local discordToken = 0 local function setDiscord(open) discordOpen = open refreshDiscordTitle() discordToken += 1 local token = discordToken local Quint = Enum.EasingStyle.Quint layoutCards(false, open and discord or nil) local textX = open and 40 or 36 tween(discordTitle, 0.4, { Position = UDim2.new(0, textX, 0, 6) }, Quint) tween(discordSub, 0.4, { Position = UDim2.new(0, textX, 0, 21), Size = UDim2.new(0, open and 102 or 106, 0, 13), }, Quint) fade(rowsItems, anyCardOpen() and 0 or 1, 0.25) fade(discordIconItems, open and 0 or 1, 0.2) if open then discordExtra.Visible = true fade(extraItems, 0) task.delay(0.15, function() if token == discordToken then fade(extraItems, 1, 0.3) end end) if not discordInfo.fetching and (not discordInfo.ok or os.clock() - discordInfo.last > 60) then task.spawn(fetchDiscord) end else fade(extraItems, 0, 0.15) tween(discordSub, 0.15, { TextColor3 = C.muted }) task.delay(0.17, function() if token == discordToken then discordExtra.Visible = false end end) end end -- Same end state as setDiscord(true), without animation (content is still hidden at launch) if DISCORD_STARTS_OPEN then discordOpen = true discordToken += 1 layoutCards(true) discordTitle.Position = UDim2.new(0, 40, 0, 6) discordSub.Position = UDim2.new(0, 40, 0, 21) discordSub.Size = UDim2.new(0, 102, 0, 13) fade(rowsItems, 0) fade(discordIconItems, 0) discordExtra.Visible = true end discord.MouseButton1Click:Connect(function() if not state.ready or state.closing or suppressClick then return end if not HAS_DISCORD then notify("Not configured", "No Discord link has been set.", "warn", "discord") return end setDiscord(not discordOpen) end) linkHit.MouseButton1Click:Connect(function() if suppressClick then return end copyLink(LINKS.discord, "Discord invite", "discord") end) linkHit.MouseEnter:Connect(function() if discordOpen then tween(discordSub, 0.15, { TextColor3 = C.accent }) end end) linkHit.MouseLeave:Connect(function() tween(discordSub, 0.15, { TextColor3 = C.muted }) end) website.MouseButton1Click:Connect(function() if not state.ready or state.closing or suppressClick then return end if not HAS_WEBSITE then notify("Not configured", "No website link has been set.", "warn", "link") return end copyLink(LINKS.website, "Website link", "link") end) local function refreshInfo() infoUI.valid.Text = formatNumber(STATS.valid) infoUI.expired.Text = formatNumber(STATS.expired) infoUI.lastUsed.Text = formatAgo(STATS.last) end refreshInfo() do local function setLabelText(label, str) if label.Text == str then return end if not state.ready then label.Text = str return end tween(label, 0.12, { TextTransparency = 1 }) task.delay(0.12, function() if state.closing then return end label.Text = str tween(label, 0.15, { TextTransparency = 0 }) end) end local infoToken = 0 local function setInfo(open) infoOpen = open infoToken += 1 local token = infoToken local Quint = Enum.EasingStyle.Quint if open then refreshInfo() end setLabelText(infoSub, open and "Key history" or "Tap to view") layoutCards(false, open and infoCard or nil) local textX = open and 40 or 36 tween(infoTitle, 0.4, { Position = UDim2.new(0, textX, 0, 6) }, Quint) tween(infoSub, 0.4, { Position = UDim2.new(0, textX, 0, 21), Size = UDim2.new(0, open and 102 or 106, 0, 13), }, Quint) fade(rowsItems, anyCardOpen() and 0 or 1, 0.25) fade(infoUI.iconItems, open and 0 or 1, 0.2) if open then infoUI.extra.Visible = true fade(infoUI.extraItems, 0) task.delay(0.15, function() if token == infoToken then fade(infoUI.extraItems, 1, 0.3) end end) else fade(infoUI.extraItems, 0, 0.15) task.delay(0.17, function() if token == infoToken then infoUI.extra.Visible = false end end) end end infoCard.MouseButton1Click:Connect(function() if not state.ready or state.closing or suppressClick then return end setInfo(not infoOpen) end) end local checkingKey = false -- While a card is expanded the Executor/Status rows stay hidden, and the small -- icon of the expanded card is replaced by its bigger one local fadeContent do local rowsHidden, discordIconHidden, infoIconHidden = {}, {}, {} for _, it in ipairs(rowsItems) do rowsHidden[it[1]] = true end for _, it in ipairs(discordIconItems) do discordIconHidden[it[1]] = true end for _, it in ipairs(infoUI.iconItems) do infoIconHidden[it[1]] = true end function fadeContent(alpha, time) if anyCardOpen() and alpha > 0 then local filtered = {} for _, it in ipairs(contentItems) do local inst = it[1] local hide = rowsHidden[inst] or (discordOpen and discordIconHidden[inst]) or (infoOpen and infoIconHidden[inst]) if not hide then filtered[#filtered + 1] = it end end fade(filtered, alpha, time) else fade(contentItems, alpha, time) end end end local function resetCheckScreen() ringScale.Scale = 0.6 for _, b in ipairs({ checkBar1, checkBar2 }) do b.frame.Visible = false b.frame.Size = UDim2.new(0, 0, 0, 3) end checkText.TextTransparency = 1 checkText.Position = UDim2.new(0, 0, 0, 162) fade(ringItems, 0) end local function drawBar(bar, time) bar.frame.Size = UDim2.new(0, 0, 0, 3) bar.frame.Position = UDim2.new(0.5, bar.a.X, 0.5, bar.a.Y) bar.frame.Visible = true local mid = (bar.a + bar.b) / 2 tween(bar.frame, time, { Size = UDim2.new(0, bar.len, 0, 3), Position = UDim2.new(0.5, mid.X, 0.5, mid.Y), }) end local function confetti(count, withPulse) local colors = C.confetti for i = 1, count do local angle = (i / count) * math.pi * 2 + math.random() * 0.3 local dist = 70 + math.random() * 45 local piece = make("Frame", { AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.new(0.5, 0, 0.5, -12), Size = UDim2.new(0, math.random(4, 7), 0, math.random(3, 5)), BackgroundColor3 = colors[math.random(#colors)], BorderSizePixel = 0, Rotation = math.random(0, 360), ZIndex = 3, }, fxLayer) make("UICorner", { CornerRadius = UDim.new(0, 2) }, piece) local t = 0.55 + math.random() * 0.3 tween(piece, t, { Position = UDim2.new(0.5, math.cos(angle) * dist, 0.5, -12 + math.sin(angle) * dist * 0.85 + 14), Rotation = piece.Rotation + math.random(-260, 260), }, Enum.EasingStyle.Quint) task.delay(t * 0.6, function() tween(piece, t * 0.8, { BackgroundTransparency = 1 }) end) task.delay(t * 1.5 + 0.2, function() piece:Destroy() end) end if withPulse then local pulse, pulseStroke = ring(fxLayer, 56, 2, C.accent, 0.2) pulse.Position = UDim2.new(0.5, 0, 0.5, -12) tween(pulse, 0.7, { Size = UDim2.new(0, 150, 0, 150) }, Enum.EasingStyle.Quint) tween(pulseStroke, 0.7, { Transparency = 1 }) task.delay(0.8, function() pulse:Destroy() end) end end local function runKeyCheck(key, isSavedKey) checkingKey = true state.ready = false notifs.dismissAll() local result task.spawn(function() if KEYLESS then result = { ok = true, valid = true } return end local ok, valid, reason = pcall(validateKey, key) result = { ok = ok, valid = valid, reason = reason } end) fadeContent(0, 0.25) task.wait(0.25) content.Visible = false spinnerHolder.Position = UDim2.new(0.5, 0, 0.5, 0) spin:Play() fade(spinnerItems, 1, 0.25) local minCheckTime = isSavedKey and SAVED_CHECK_TIME or CHECK_TIME local t0 = os.clock() repeat task.wait() until (result and os.clock() - t0 >= minCheckTime) or os.clock() - t0 > 15 if not (result and result.ok and result.valid) then fade(spinnerItems, 0, 0.25) task.wait(0.25) spin:Cancel() content.Visible = true fadeContent(1, 0.35) if result and result.ok then local detail = result.reason and tostring(result.reason) or "That key isn't valid. Get a new one." if detail:lower():find("expir") then STATS.expired += 1 saveStats() refreshInfo() end notify("Invalid key", detail, "error") else local detail = result and result.valid and tostring(result.valid) or "Couldn't check your key. Try again." notify("Something went wrong", detail, "error") end task.wait(0.35) state.ready = true checkingKey = false return end if KEYLESS then statusValue.Text = "Keyless" setRole(statusValue, "TextColor3", "accent") checkText.Text = "Keyless Access!" else statusValue.Text = "Key valid" setRole(statusValue, "TextColor3", "success") checkText.Text = isSavedKey and "Saved Key Found!" or "Correct Key!" if KEY_SAVE then safeWriteFile(KEY_FILE, key) end STATS.valid += 1 STATS.last = os.time() saveStats() end fade(spinnerItems, 0, 0.25) task.wait(0.25) spin:Cancel() resetCheckScreen() checkScreen.Visible = true fade(ringItems, 1, 0.25) tween(ringScale, 0.45, { Scale = 1 }, Enum.EasingStyle.Back) task.wait(isSavedKey and 0.15 or 0.4) drawBar(checkBar1, 0.14) task.wait(0.14) drawBar(checkBar2, 0.22) task.wait(0.22) if isSavedKey then confetti(10, false) else confetti(22, true) task.delay(0.3, function() confetti(12, false) end) end task.wait(isSavedKey and 0.2 or 1) tween(checkText, 0.3, { TextTransparency = 0, Position = UDim2.new(0, 0, 0, 156) }, Enum.EasingStyle.Quint) task.wait(isSavedKey and 0.35 or 1) snapLocked = true fade(ringItems, 0, 0.2) tween(checkText, 0.2, { TextTransparency = 1 }) task.wait(0.2) checkScreen.Visible = false local morphSpec = buildMorph(notifs.styleKey()) morph.Visible = true morphSpec.spin:Play() Blur.acquire() local vp = root.AbsoluteSize local targetX, targetY if morphSpec.top then targetX = vp.X / 2 targetY = 12 + morphSpec.h / 2 else targetX = vp.X - 16 - morphSpec.w / 2 targetY = vp.Y - 16 - morphSpec.h / 2 end tween(main, 0.7, { Size = UDim2.new(0, morphSpec.w, 0, morphSpec.h), Position = UDim2.new(0, targetX, 0, targetY), }, Enum.EasingStyle.Quart, Enum.EasingDirection.InOut) tween(canvas, 0.7, { BackgroundColor3 = morphSpec.bg, BackgroundTransparency = morphSpec.bgTransparency }) tween(canvasCorner, 0.7, { CornerRadius = UDim.new(0, morphSpec.radius) }) tween(decorGroup, 0.4, { GroupTransparency = 1 }) tween(shadow, 0.5, { ImageTransparency = 1 }) tween(borderStroke, 0.5, { Transparency = morphSpec.borderTransparency, Color = morphSpec.border }) task.delay(0.35, function() fade(morphSpec.items, 1, 0.3) end) task.wait(0.75) task.wait(isSavedKey and 0.2 or 1) local runError task.spawn(function() local callback = cfg.Callback if type(callback) == "string" and callback ~= "" then if not loadstring then runError = "loadstring is not available" return end local fn, compileError = loadstring(callback) if not fn then runError = compileError return end callback = fn end if type(callback) == "function" then local ok, err = pcall(callback, key) if not ok then runError = err end end end) task.wait(0.3) morphSpec.spin:Cancel() Blur.release() fade(morphSpec.items, 0, 0.25) tween(canvas, 0.3, { BackgroundTransparency = 1 }) tween(borderStroke, 0.3, { Transparency = 1 }) task.wait(0.35) if runError then notify("Script error", tostring(runError):sub(1, 80), "error", nil, 5) task.wait(5.5) end root:Destroy() end submit.MouseButton1Click:Connect(function() if not state.ready or state.closing or checkingKey then return end if KEYLESS then runKeyCheck("") -- the Callback receives an empty key in keyless mode return end local key = keyBox.Text:match("^%s*(.-)%s*$") if key == "" then notify("Empty key", "Paste your key in the box first.", "warn", "key") return end runKeyCheck(key) end) -- Fechar a UI (o X fecha direto, sem popup de confirmação) closeGui = function() if state.closing then return end state.closing = true state.ready = false notifs.dismissAll() tintTo(closeIcon, C.muted) tween(closeBtn, 0.15, { BackgroundTransparency = 1 }) if not SHOW_INTRO then -- No intro: plain fade-out fadeContent(0, 0.3) ctx.pages.fadeOut(0.3) tween(canvas, 0.35, { BackgroundTransparency = 1 }) tween(decorGroup, 0.35, { GroupTransparency = 1 }) tween(borderStroke, 0.35, { Transparency = 1 }) tween(shadow, 0.35, { ImageTransparency = 1 }) task.wait(0.4) root:Destroy() return end fadeContent(0, 0.2) ctx.pages.fadeOut(0.2) task.wait(0.2) content.Visible = false introLogo.Position = UDim2.new(0.5, 0, 0.5, 0) tween(introLogo, 0.4, { ImageTransparency = 0 }) tween(borderStroke, 0.5, { Transparency = 0.55 }) tween(main, 0.65, { Size = UDim2.new(0, INTRO_SIZE, 0, INTRO_SIZE) }, Enum.EasingStyle.Quart, Enum.EasingDirection.InOut) task.wait(0.7) tween(canvas, 0.35, { BackgroundTransparency = 1 }) tween(decorGroup, 0.35, { GroupTransparency = 1 }) tween(introLogo, 0.35, { ImageTransparency = 1 }) tween(borderStroke, 0.35, { Transparency = 1 }) tween(shadow, 0.35, { ImageTransparency = 1 }) task.wait(0.4) root:Destroy() end closeBtn.MouseButton1Click:Connect(function() if not state.ready or state.closing then return end task.spawn(closeGui) end) -- Hovers closeBtn.MouseEnter:Connect(function() if not state.ready or state.closing then return end tween(closeBtn, 0.15, { BackgroundTransparency = 0 }) tintTo(closeIcon, C.text) end) closeBtn.MouseLeave:Connect(function() if not state.ready or state.closing then return end tween(closeBtn, 0.15, { BackgroundTransparency = 1 }) tintTo(closeIcon, C.muted) end) moonBtn.MouseEnter:Connect(function() if not state.ready or state.closing then return end tween(moonBtn, 0.15, { BackgroundTransparency = 0 }) tintTo(moonIcon, C.text) end) moonBtn.MouseLeave:Connect(function() tween(moonBtn, 0.15, { BackgroundTransparency = 1 }) tintTo(moonIcon, C.muted) end) local THEME_ANIM_TIME = 1.6 local switchingTheme = false local function switchTheme() if not state.ready or state.closing or checkingKey or switchingTheme then return end switchingTheme = true state.ready = false notifs.dismissAll() tintTo(moonIcon, C.muted) tween(moonBtn, 0.15, { BackgroundTransparency = 1 }) fadeContent(0, 0.25) task.wait(0.25) content.Visible = false spinnerHolder.Position = UDim2.new(0.5, 0, 0.5, 0) spin:Play() fade(spinnerItems, 1, 0.25) task.wait(0.4) themeIndex = themeIndex % #THEME_ORDER + 1 local name = THEME_ORDER[themeIndex] applyTheme(name, THEME_ANIM_TIME) task.wait(THEME_ANIM_TIME + 0.3) fade(spinnerItems, 0, 0.25) task.wait(0.25) spin:Cancel() content.Visible = true fadeContent(1, 0.35) notify("Theme: " .. name, "Theme applied.", "info", "moon") task.wait(0.35) state.ready = true switchingTheme = false end moonBtn.MouseButton1Click:Connect(function() task.spawn(switchTheme) end) root.Parent = game:GetService("CoreGui") local function snap() if snapLocked then return end local size = root.AbsoluteSize main.Position = UDim2.new(0, math.floor(size.X / 2), 0, math.floor(size.Y / 2)) end snap() root:GetPropertyChangedSignal("AbsoluteSize"):Connect(snap) task.spawn(function() if SHOW_INTRO then main.Size = UDim2.new(0, INTRO_SIZE - 20, 0, INTRO_SIZE - 20) tween(main, 0.6, { Size = UDim2.new(0, INTRO_SIZE, 0, INTRO_SIZE) }, Enum.EasingStyle.Quint) tween(canvas, 0.5, { BackgroundTransparency = 0 }) tween(decorGroup, 0.5, { GroupTransparency = 0 }) tween(introLogo, 0.5, { ImageTransparency = 0 }) if SHOW_SQUARE_CONTORN then tween(borderStroke, 0.5, { Transparency = 0.55 }) end tween(shadow, 0.5, { ImageTransparency = 0.6 }) task.wait(SQUARE_TIME) tween(borderStroke, 0.7, { Transparency = 1 }) tween(main, 0.85, { Size = UDim2.new(0, FINAL_W, 0, FINAL_H) }, Enum.EasingStyle.Quint) tween(introLogo, 0.7, { Position = UDim2.new(0.5, 0, 0.5, -20) }, Enum.EasingStyle.Quint) task.wait(0.35) spin:Play() fade(spinnerItems, 1, 0.4) task.wait(LOADING_TIME) fade(spinnerItems, 0, 0.3) tween(introLogo, 0.3, { ImageTransparency = 1 }) task.wait(0.2) spin:Cancel() else -- No intro animation: sit at final size, invisible, for LoadingTime (still -- needed to detect the game/executor and let icons finish preloading), -- then simply fade the whole window in. main.Size = UDim2.new(0, FINAL_W, 0, FINAL_H) task.wait(LOADING_TIME) tween(canvas, 0.5, { BackgroundTransparency = 0 }) tween(decorGroup, 0.5, { GroupTransparency = 0 }) tween(shadow, 0.5, { ImageTransparency = 0.6 }) task.wait(0.25) end -- Make sure every icon/image finished preloading before the Key System -- content itself is loaded and shown. while not iconsPreloaded do task.wait() end content.Visible = true fadeContent(1, 0.45) task.wait(0.3) state.ready = true if KEYLESS then if KL.autoconfirm and not checkingKey then task.wait(0.15) runKeyCheck("") -- the Callback receives an empty key in keyless mode end elseif SAVED_KEY and not checkingKey then keyBox.Text = SAVED_KEY task.wait(0.15) runKeyCheck(SAVED_KEY, true) end end) -- KeySystem.new(...) returns this object: :SetGetkeyTitle / :SetGetkeyIcon, and everything else -- (Destroy, Enabled, Parent, ...) is forwarded to the ScreenGui. local api = {} function api:SetGetkeyTitle(title) UI.SetGetkeyTitle(title) return self end function api:SetGetkeyIcon(icon) UI.SetGetkeyIcon(icon) return self end function api:SetNotifStyle(style) UI.SetNotifStyle(style) return self end api.NotifStyle = api.SetNotifStyle function api:SetTabsStyle(style) UI.SetTabsStyle(style) return self end api.TabsStyle = api.SetTabsStyle function api:GetMethod(entry) UI.GetMethod(entry) return self end function api:SetUIFont(font) UI.SetUIFont(font) return self end function api:SetTitleFont(font) UI.SetTitleFont(font) return self end -- OphynWindow:Tab({ Title = "...", Icon = "..." }) -> Tab (same as OphynWindow({ ... })) function api:Tab(props) return ctx.pages.createTab(props) end api.Gui = root return setmetatable(api, { __call = function(_, props) return ctx.pages.createTab(props) end, __index = function(_, key) local value = root[key] if type(value) == "function" then return function(_, ...) return value(root, ...) end end return value end, __newindex = function(_, key, value) root[key] = value end, }) end return UI end __modules["images/images"] = function() -- src/images/images.lua -- All Roblox asset IDs (images, icons, and font) used by the UI. local Images = { FONT = "rbxassetid://12187365364", KEY = "rbxassetid://96510194465420", SUBMIT = "rbxassetid://113692007244654", LINK = "rbxassetid://114238209622913", DISCORD = "rbxassetid://127255077587058", GLOW = "rbxassetid://8992230677", LOGO = "rbxassetid://111673746737789", CLOSE_ICON = "rbxassetid://110786993356448", MOON_ICON = "rbxassetid://83380517901735", SHADOW = "rbxassetid://6014261993", GAME_PLACEHOLDER = "rbxassetid://74584987850498", KEYLESS = "rbxassetid://130551565616516", } return Images end __modules["utilities/jnkie"] = function() local SDK_URL = "https://jnkie.com/sdk/library.lua" local Jnkie = {} Jnkie.__index = Jnkie local function safeLoad(url) if not loadstring then return nil, "loadstring is not available" end local ok, result = pcall(function() return game:HttpGet(url) end) if not ok then return nil, tostring(result) end local fn, compileErr = loadstring(result) if not fn then return nil, tostring(compileErr) end local okRun, lib = pcall(fn) if not okRun then return nil, tostring(lib) end return lib end function Jnkie.new(config) config = config or {} local self = setmetatable({}, Jnkie) self.__isJnkieInstance = true self.service = config.Service or config.service self.identifier = config.Identifier or config.identifier self.provider = config.Provider or config.provider or "Mixed" self.client = nil self.loadError = nil if not self.service or self.service == "" then warn("[Jnkie] Service is missing — check your dashboard for the exact name") end if not self.identifier or self.identifier == "" then warn("[Jnkie] Identifier is missing — check your dashboard for your user ID") end return self end function Jnkie:_client() if self.client then return self.client end local lib, err = safeLoad(SDK_URL) if not lib then self.loadError = err warn("[Jnkie] failed to load SDK: " .. tostring(err)) return nil end lib.service = self.service lib.identifier = self.identifier lib.provider = self.provider self.client = lib return lib end local function isSuccess(result) if type(result) ~= "table" then return false end if result.valid == true or result.success == true then return true end if result.message == "KEY_VALID" or result.message == "KEYLESS" then return true end return false end function Jnkie:CheckKey(key) local lib = self:_client() if not lib then return { valid = false, error = self.loadError or "SDK_LOAD_FAILED" } end local ok, result = pcall(lib.check_key, key) if not ok then return { valid = false, error = tostring(result) } end if type(result) ~= "table" then return { valid = false, error = "UNEXPECTED_RESPONSE: " .. tostring(result) } end result.valid = isSuccess(result) return result end function Jnkie:GetKeyLink() local lib = self:_client() if not lib then return nil, self.loadError or "SDK_LOAD_FAILED" end local ok, link, err = pcall(lib.get_key_link) if not ok then return nil, tostring(link) end return link, err end function Jnkie:Validator() local instance = self local adapter = setmetatable({ __isJnkie = true, __instance = instance, }, { __call = function(_, key) local result = instance:CheckKey(key) local reason = result and (result.error or result.message) return result and result.valid == true, reason end, }) return adapter end return Jnkie end __modules["utilities/lucide"] = function() -- src/utilities/lucide.lua -- Lucide icon support, backed by https://github.com/Footagesus/Icons (lucide/dist/Icons.lua). -- -- Anywhere the UI takes an `Icon`, you can now pass a Lucide name instead of an asset id: -- -- Tab:Section({ Title = "Main", Icon = "house" }) -- Tab:Section({ Title = "Main", Icon = "lucide:house" }) -- same thing, explicit prefix -- -- Asset ids ("rbxassetid://...", a bare number, "rbxthumb://...") keep working exactly as before. -- -- The icon pack is a spritesheet: every icon is a rect inside a bigger image, so a resolved -- icon is { Image, RectSize, RectOffset } and not just one asset id. The pack is only -- downloaded the first time a Lucide name is actually used (and cached after that), so -- scripts that only use asset ids never pay for it. local Lucide = {} local PACK_URL = "https://raw.githubusercontent.com/Footagesus/Icons/refs/heads/main/lucide/dist/Icons.lua" local PREFIX = "lucide:" local pack = nil -- the loaded icon pack local failed = false -- the download/parse failed, don't keep retrying local loading = false local preloaded = {} -- spritesheets that already went through ContentProvider local warned = {} -- names that already printed a warning local function fetch(url) local ok, body = pcall(function() return game:HttpGet(url) end) if ok and type(body) == "string" and body ~= "" then return body end ok, body = pcall(function() return game:HttpGetAsync(url) end) if ok and type(body) == "string" and body ~= "" then return body end return nil end local function loadPack() if pack or failed then return pack end if loading then -- another thread is already downloading it: wait for that one while loading do task.wait() end return pack end loading = true local ok, result = pcall(function() local body = fetch(PACK_URL) if not body then error("could not download the icon pack") end local chunk, err = loadstring(body) if not chunk then error(err) end return chunk() end) loading = false if ok and type(result) == "table" then pack = result else failed = true warn("[Ophyn] Lucide icons unavailable: " .. tostring(result)) end return pack end -- "rbxassetid://123" / 123 / "123" -> "rbxassetid://123"; anything else string-like is kept local function toAsset(value) if type(value) == "number" then return "rbxassetid://" .. tostring(math.floor(value)) end if type(value) == "string" and value:match("^%d+$") then return "rbxassetid://" .. value end return value end -- true when `value` should be looked up in the Lucide pack (instead of used as an asset id) function Lucide.isName(value) if type(value) ~= "string" or value == "" then return false end if value:match("^%d+$") then return false -- bare asset id end if value:match("^rbx%a*://") or value:match("^https?://") then return false -- rbxassetid:// / rbxthumb:// / rbxasset:// / urls end return true end local function stripPrefix(name) if name:sub(1, #PREFIX):lower() == PREFIX then return name:sub(#PREFIX + 1) end return name end local function preload(sheet) if preloaded[sheet] then return end preloaded[sheet] = true task.spawn(function() pcall(function() game:GetService("ContentProvider"):PreloadAsync({ sheet }) end) end) end -- Returns { Image = "rbxassetid://...", RectSize = Vector2, RectOffset = Vector2 } -- or nil when the name is unknown (or the pack could not be loaded). function Lucide.resolve(value) if not Lucide.isName(value) then return nil end local name = stripPrefix(value):lower():gsub("_", "-") local loaded = loadPack() if not loaded then return nil end local icons = loaded.Icons or loaded local entry = type(icons) == "table" and icons[name] or nil if type(entry) ~= "table" then if not warned[name] then warned[name] = true warn('[Ophyn] unknown Lucide icon "' .. tostring(value) .. '"') end return nil end local sheet = entry.Image if type(loaded.Spritesheets) == "table" and loaded.Spritesheets[tostring(entry.Image)] ~= nil then sheet = loaded.Spritesheets[tostring(entry.Image)] end sheet = toAsset(sheet) if type(sheet) ~= "string" then return nil end preload(sheet) return { Image = sheet, RectSize = entry.ImageRectSize or Vector2.new(0, 0), RectOffset = entry.ImageRectPosition or entry.ImageRectOffset or Vector2.new(0, 0), } end -- Points an ImageLabel/ImageButton at `value`, which can be a Lucide name or an asset id. -- Always resets the sprite rect, so an icon can be swapped between the two kinds safely. function Lucide.apply(label, value) local sprite = Lucide.resolve(value) if sprite then label.Image = sprite.Image label.ImageRectSize = sprite.RectSize label.ImageRectOffset = sprite.RectOffset return true end label.ImageRectSize = Vector2.new(0, 0) label.ImageRectOffset = Vector2.new(0, 0) if Lucide.isName(value) then label.Image = "" -- a Lucide name that could not be resolved: draw nothing return false end label.Image = value or "" return value ~= nil end return Lucide end __modules["utilities/panda"] = function() local LIB_URL = "https://secure.pandauth.com/pv4/lib" local REASONS = { INVALID_KEY = "key is invalid or expired.", RATE_LIMITED = "you are being rate limited, please wait a moment and try again.", NETWORK = "network error, please try again.", NO_SERVICE = "Panda ServiceId is missing or invalid.", NO_KEY = "key is empty.", NO_HTTP = "your executor doesn't support HTTP requests.", IDENTITY = "couldn't verify the Panda server identity, please try again later.", PROTOCOL = "Panda protocol error, please try again later.", } local Panda = {} Panda.__index = Panda function Panda.new(config) config = config or {} local self = setmetatable({}, Panda) local serviceId = config.ServiceId or config.Service or config.serviceId self.serviceId = serviceId ~= nil and tostring(serviceId) or "" self.debug = config.Debug == true self.lib = nil self.loading = false if self.serviceId == "" then warn("[Panda] ServiceId is missing — check your Panda dashboard") end return self end function Panda:_load() while self.loading do task.wait(0.1) end if self.lib then return self.lib end if self.serviceId == "" then return nil, REASONS.NO_SERVICE end self.loading = true local lib, err local okFetch, src = pcall(function() return game:HttpGet(LIB_URL) end) if not okFetch or type(src) ~= "string" or src == "" then err = "couldn't download the Panda library." elseif not loadstring then err = "loadstring is not available." else local fn, compileError = loadstring(src) if not fn then err = "couldn't load the Panda library: " .. tostring(compileError) else local okRun, result = pcall(fn) if okRun and type(result) == "table" and type(result.configure) == "function" then local okConfig, configError = pcall(result.configure, { serviceId = self.serviceId, debug = self.debug, kickOnDetect = false, }) if okConfig then lib = result else err = "couldn't configure the Panda library: " .. tostring(configError) end else err = "Panda library failed to initialize." end end end self.loading = false if lib then self.lib = lib return lib end return nil, err end function Panda:CheckKey(key) key = tostring(key or ""):match("^%s*(.-)%s*$") if key == "" then return false, REASONS.NO_KEY end local lib, err = self:_load() if not lib then return false, err end if type(lib.validateEx) == "function" then local ok, valid, reason = pcall(lib.validateEx, key) if not ok then return false, tostring(valid) end if valid == true then return true end return false, REASONS[reason] or ("Panda error: " .. tostring(reason)) end local ok, result = pcall(lib.validate, key) if not ok then return false, tostring(result) end if type(result) == "table" and result.success == true then return true end local reason = type(result) == "table" and (result.reason or result.error) or nil return false, REASONS[reason] or tostring(reason or "key is invalid.") end function Panda:GetKeyLink() local lib, err = self:_load() if not lib then return nil, err end if type(lib.getKeyUrl) ~= "function" then return nil, "Panda library has no getKeyUrl." end local ok, url = pcall(lib.getKeyUrl) if ok and type(url) == "string" and url ~= "" then return url end return nil, "Failed to get link." end return Panda end __modules["utilities/platoboost"] = function() local HttpService = game:GetService("HttpService") local Players = game:GetService("Players") -- SHA-256 (hex digest) from the official Platoboost library. local sha256 = (function() local a=2^32;local b=a-1;local function c(d,e)local f,g=0,1;while d~=0 or e~=0 do local h,i=d%2,e%2;local j=(h+i)%2;f=f+j*g;d=math.floor(d/2)e=math.floor(e/2)g=g*2 end;return f%a end;local function k(d,e,l,...)local m;if e then d=d%a;e=e%a;m=c(d,e)if l then m=k(m,l,...)end;return m elseif d then return d%a else return 0 end end;local function n(d,e,l,...)local m;if e then d=d%a;e=e%a;m=(d+e-c(d,e))/2;if l then m=n(m,l,...)end;return m elseif d then return d%a else return b end end;local function o(p)return b-p end;local function q(d,r)if r<0 then return lshift(d,-r)end;return math.floor(d%2^32/2^r)end;local function s(p,r)if r>31 or r<-31 then return 0 end;return q(p%a,r)end;local function lshift(d,r)if r<0 then return s(d,-r)end;return d*2^r%2^32 end;local function t(p,r)p=p%a;r=r%32;local u=n(p,2^r-1)return s(p,r)+lshift(u,32-r)end;local v={0x428a2f98,0x71374491,0xb5c0fbcf,0xe9b5dba5,0x3956c25b,0x59f111f1,0x923f82a4,0xab1c5ed5,0xd807aa98,0x12835b01,0x243185be,0x550c7dc3,0x72be5d74,0x80deb1fe,0x9bdc06a7,0xc19bf174,0xe49b69c1,0xefbe4786,0x0fc19dc6,0x240ca1cc,0x2de92c6f,0x4a7484aa,0x5cb0a9dc,0x76f988da,0x983e5152,0xa831c66d,0xb00327c8,0xbf597fc7,0xc6e00bf3,0xd5a79147,0x06ca6351,0x14292967,0x27b70a85,0x2e1b2138,0x4d2c6dfc,0x53380d13,0x650a7354,0x766a0abb,0x81c2c92e,0x92722c85,0xa2bfe8a1,0xa81a664b,0xc24b8b70,0xc76c51a3,0xd192e819,0xd6990624,0xf40e3585,0x106aa070,0x19a4c116,0x1e376c08,0x2748774c,0x34b0bcb5,0x391c0cb3,0x4ed8aa4a,0x5b9cca4f,0x682e6ff3,0x748f82ee,0x78a5636f,0x84c87814,0x8cc70208,0x90befffa,0xa4506ceb,0xbef9a3f7,0xc67178f2}local function w(x)return string.gsub(x,".",function(l)return string.format("%02x",string.byte(l))end)end;local function y(z,A)local x=""for B=1,A do local C=z%256;x=string.char(C)..x;z=(z-C)/256 end;return x end;local function D(x,B)local A=0;for B=B,B+3 do A=A*256+string.byte(x,B)end;return A end;local function E(F,G)local H=64-(G+9)%64;G=y(8*G,8)F=F.."\128"..string.rep("\0",H)..G;assert(#F%64==0)return F end;local function I(J)J[1]=0x6a09e667;J[2]=0xbb67ae85;J[3]=0x3c6ef372;J[4]=0xa54ff53a;J[5]=0x510e527f;J[6]=0x9b05688c;J[7]=0x1f83d9ab;J[8]=0x5be0cd19;return J end;local function K(F,B,J)local L={}for M=1,16 do L[M]=D(F,B+(M-1)*4)end;for M=17,64 do local N=L[M-15]local O=k(t(N,7),t(N,18),s(N,3))N=L[M-2]L[M]=(L[M-16]+O+L[M-7]+k(t(N,17),t(N,19),s(N,10)))%a end;local d,e,l,P,Q,R,S,T=J[1],J[2],J[3],J[4],J[5],J[6],J[7],J[8]for B=1,64 do local O=k(t(d,2),t(d,13),t(d,22))local U=k(n(d,e),n(d,l),n(e,l))local V=(O+U)%a;local W=k(t(Q,6),t(Q,11),t(Q,25))local X=k(n(Q,R),n(o(Q),S))local Y=(T+W+X+v[B]+L[B])%a;T=S;S=R;R=Q;Q=(P+Y)%a;P=l;l=e;e=d;d=(Y+V)%a end;J[1]=(J[1]+d)%a;J[2]=(J[2]+e)%a;J[3]=(J[3]+l)%a;J[4]=(J[4]+P)%a;J[5]=(J[5]+Q)%a;J[6]=(J[6]+R)%a;J[7]=(J[7]+S)%a;J[8]=(J[8]+T)%a end;local function Z(F)F=E(F,#F)local J=I({})for B=1,#F,64 do K(F,B,J)end;return w(y(J[1],4)..y(J[2],4)..y(J[3],4)..y(J[4],4)..y(J[5],4)..y(J[6],4)..y(J[7],4)..y(J[8],4))end; return Z end)() local Platoboost = {} Platoboost.__index = Platoboost -- Tried in this order; the first one that answers is used. local HOSTS = { "https://api.platoboost.app", "https://api.platoboost.com", "https://api.platoboost.net" } local LINK_CACHE_TIME = 10 * 60 local RATE_LIMIT_MESSAGE = "you are being rate limited, please wait 20 seconds and try again." local BAD_STATUS_MESSAGE = "server returned an invalid status code, please try again later." local JSON_HEADERS = { ["Content-Type"] = "application/json" } local rng = Random.new() local function getRequestFunction() return request or http_request or (syn and syn.request) or (http and http.request) end local function getHwid() if gethwid then local ok, hwid = pcall(gethwid) if ok and hwid ~= nil and tostring(hwid) ~= "" then return tostring(hwid) end end local lp = Players.LocalPlayer return tostring(lp and lp.UserId or 0) end local function generateNonce() local chars = table.create(16) for i = 1, 16 do chars[i] = string.char(rng:NextInteger(97, 122)) end return table.concat(chars) end local function decode(body) local ok, result = pcall(HttpService.JSONDecode, HttpService, body) if ok and type(result) == "table" then return result end return nil end function Platoboost.new(config) config = config or {} local self = setmetatable({}, Platoboost) self.__isPlatoboostInstance = true local service = config.ServiceId or config.Service or config.service self.service = tonumber(service) or service self.secret = config.Secret or config.secret local useNonce = config.UseNonce if useNonce == nil then useNonce = config.useNonce end self.useNonce = useNonce ~= false -- Optional: force one API host, e.g. Host = "https://api.platoboost.app" local host = config.Host or config.host if type(host) == "string" and host ~= "" then host = host:gsub("/+$", "") if not host:match("^https?://") then host = "https://" .. host end self.host = host end self.identifier = nil self.requestSending = false self.cachedLink = nil self.cachedTime = 0 if self.service == nil or self.service == "" then warn("[Platoboost] ServiceId is missing — check your Platoboost dashboard") end if self.useNonce and (type(self.secret) ~= "string" or self.secret == "") then warn("[Platoboost] Secret is missing — keys can't be verified without it") end return self end -- Picks the first host that answers /public/connectivity (200 or 429). -- If none answers, the first one in HOSTS is used. function Platoboost:_host() if self.host then return self.host end local req = getRequestFunction() if req then for _, host in ipairs(HOSTS) do local ok, res = pcall(req, { Url = host .. "/public/connectivity", Method = "GET" }) if ok and type(res) == "table" and (res.StatusCode == 200 or res.StatusCode == 429) then self.host = host return self.host end end end self.host = HOSTS[1] return self.host end function Platoboost:_identifier() if not self.identifier then self.identifier = sha256(getHwid()) end return self.identifier end function Platoboost:_send(options) local req = getRequestFunction() if not req then return nil, "your executor doesn't support HTTP requests." end local ok, res = pcall(req, options) if not ok then return nil, tostring(res) end if type(res) ~= "table" then return nil, "invalid response from server." end return res end -- Returns link, or nil + reason function Platoboost:GetKeyLink() if self.cachedLink and self.cachedTime + LINK_CACHE_TIME > os.time() then return self.cachedLink end if self.service == nil or self.service == "" then return nil, "Platoboost ServiceId is missing." end local res, err = self:_send({ Url = self:_host() .. "/public/start", Method = "POST", Body = HttpService:JSONEncode({ service = self.service, identifier = self:_identifier(), }), Headers = JSON_HEADERS, }) if not res then return nil, err end if res.StatusCode == 200 then local decoded = decode(res.Body) if decoded then if decoded.success == true and type(decoded.data) == "table" and decoded.data.url then self.cachedLink = decoded.data.url self.cachedTime = os.time() return self.cachedLink end return nil, tostring(decoded.message or "Failed to get link.") end elseif res.StatusCode == 429 then return nil, RATE_LIMIT_MESSAGE end return nil, "Failed to get link." end -- With UseNonce the server signs its answer with the secret; check it. function Platoboost:_integrityOk(data, nonce) if not self.useNonce then return true end return data.hash == sha256("true" .. "-" .. nonce .. "-" .. tostring(self.secret)) end function Platoboost:_redeem(key) local nonce = generateNonce() local body = { identifier = self:_identifier(), key = key, } if self.useNonce then body.nonce = nonce end local res, err = self:_send({ Url = self:_host() .. "/public/redeem/" .. tostring(self.service), Method = "POST", Body = HttpService:JSONEncode(body), Headers = JSON_HEADERS, }) if not res then return false, err end if res.StatusCode == 429 then return false, RATE_LIMIT_MESSAGE end if res.StatusCode ~= 200 then return false, BAD_STATUS_MESSAGE end local decoded = decode(res.Body) if not decoded then return false, "invalid response from server." end if decoded.success ~= true then local message = tostring(decoded.message or "request failed.") if message:sub(1, 27) == "unique constraint violation" then return false, "you already have an active key, please wait for it to expire before redeeming it." end return false, message end local data = type(decoded.data) == "table" and decoded.data or {} if data.valid ~= true then return false, "key is invalid." end if not self:_integrityOk(data, nonce) then return false, "failed to verify integrity." end return true end function Platoboost:_verify(key) local nonce = generateNonce() local url = self:_host() .. "/public/whitelist/" .. tostring(self.service) .. "?identifier=" .. self:_identifier() .. "&key=" .. HttpService:UrlEncode(key) if self.useNonce then url = url .. "&nonce=" .. nonce end local res, err = self:_send({ Url = url, Method = "GET" }) if not res then return false, err end if res.StatusCode == 429 then return false, RATE_LIMIT_MESSAGE end if res.StatusCode ~= 200 then return false, BAD_STATUS_MESSAGE end local decoded = decode(res.Body) if not decoded then return false, "invalid response from server." end if decoded.success ~= true then return false, tostring(decoded.message or "request failed.") end local data = type(decoded.data) == "table" and decoded.data or {} if data.valid == true then if not self:_integrityOk(data, nonce) then return false, "failed to verify integrity." end return true end -- Keys from the Platoboost site start with KEY_ and must be redeemed first if key:sub(1, 4) == "KEY_" then return self:_redeem(key) end return false, "key is invalid." end -- Returns valid (boolean), reason (string when invalid) function Platoboost:CheckKey(key) key = tostring(key or ""):match("^%s*(.-)%s*$") if key == "" then return false, "key is empty." end if self.service == nil or self.service == "" then return false, "Platoboost ServiceId is missing." end if self.useNonce and (type(self.secret) ~= "string" or self.secret == "") then return false, "Platoboost Secret is missing." end if self.requestSending then return false, "a request is already being sent, please slow down." end self.requestSending = true local ok, valid, reason = pcall(self._verify, self, key) self.requestSending = false if not ok then return false, tostring(valid) end return valid == true, reason end function Platoboost:Validator() local instance = self return setmetatable({ __isPlatoboost = true, __instance = instance, }, { __call = function(_, key) return instance:CheckKey(key) end, }) end return Platoboost end __modules["utilities/unoauth"] = function() local HttpService = game:GetService("HttpService") local Players = game:GetService("Players") local UnoAuth = {} UnoAuth.__index = UnoAuth function UnoAuth.new(config) config = config or {} local self = setmetatable({}, UnoAuth) self.__isUnoAuthInstance = true self.AppId = config.AppId or config.app_id or "" self.ServerUrl = (config.ServerUrl or config.server_url or "https://unoauth.su"):gsub("/+$", "") self.AppName = config.AppName or "Roblox Script" self.Hwid = config.Hwid self.UserData = {} return self end local function getHwid() local attempts = { function() return gethwid and gethwid() end, function() return get_hwid and get_hwid() end, function() return getgenv and getgenv().gethwid and getgenv().gethwid() end, function() return syn and syn.get_hwid and syn.get_hwid() end, function() return fluxus and fluxus.get_hwid and fluxus.get_hwid() end, function() return game:GetService("RbxAnalyticsService"):GetClientId() end } for _, f in ipairs(attempts) do local ok, val = pcall(f) if ok and val and type(val) == "string" and #val > 3 then return val end end local lp = Players.LocalPlayer return lp and ("RBX-UID-" .. tostring(lp.UserId)) or "RBX-DEFAULT-DEVICE" end local function httpRequest(params) local fn = (syn and syn.request) or (http and http.request) or http_request or request or (fluxus and fluxus.request) or (krnl and krnl.request) if fn then local ok, res = pcall(fn, { Url = params.Url, Method = params.Method or "GET", Headers = params.Headers or {}, Body = params.Body }) if ok and type(res) == "table" then local code = res.StatusCode or res.statusCode or res.status_code or 200 local body = res.Body or res.body or res.data or "" return tonumber(code) or 200, body elseif ok and type(res) == "string" then return 200, res end end local ok, res = pcall(function() if params.Method == "POST" then return HttpService:PostAsync(params.Url, params.Body or "", Enum.HttpContentType.ApplicationJson) else return HttpService:GetAsync(params.Url) end end) return ok and 200 or 500, tostring(res) end function UnoAuth:CheckKey(key) key = tostring(key or ""):match("^%s*(.-)%s*$") if key == "" then return false, "Ключ пустой" end local lp = Players.LocalPlayer local payload = { key = key, hwid = self.Hwid or getHwid(), appId = self.AppId, roblox_user = lp and lp.Name or "UnknownPlayer", roblox_id = lp and lp.UserId or 0 } local status, body = httpRequest({ Url = self.ServerUrl .. "/api/v1/roblox/activate", Method = "POST", Headers = { ["Content-Type"] = "application/json" }, Body = HttpService:JSONEncode(payload) }) local ok, data = pcall(function() return HttpService:JSONDecode(body) end) if not ok or type(data) ~= "table" then return false, "Ошибка связи с сервером (" .. tostring(status) .. ")" end if data.valid or data.success then self.UserData = data return true end return false, data.error or "Недействительный ключ" end function UnoAuth:GetKeyLink() if self.AppId and self.AppId ~= "" then return self.ServerUrl .. "/portal?app=" .. tostring(self.AppId) end return self.ServerUrl end function UnoAuth:Validator() local instance = self return setmetatable({ __isUnoAuth = true, __instance = instance, }, { __call = function(_, key) return instance:CheckKey(key) end, }) end return UnoAuth end __modules["variables"] = function() return { -- Window Config Title = "Ophyn", Description = "Key System", Logo = "rbxassetid://111673746737789", -- rbxassetid Theme = "Plant-Dark", Folder = "Ophyn-KSY", -- Buttons Config getkey = true, -- Intro Config Intro = "true", -- "false": fade-in on open, fade-out on close startintro_size = 80, -- initial square size squareintro_time = 1.2, squarecontorn = "true", -- "false": removes the outline around the intro square -- Themes Config Changelogocolor = true, Changeiconscolor = true, ChangeTheme = "true", -- "false": disable moon icon to change Theme -- Section Config discord_link = "", website_link = "", -- Cards ("true" / "false") Discord = "true", Website = "false", Informations = "true", -- Keyless mode: no key needed. Status becomes "Keyless" and Submit runs the Callback directly. Keyless = { enabled = false, -- true: turns keyless mode on disabletextbox = true, -- dims the key box and blocks typing disablegetkey = true, -- dims "Get a key" and blocks clicks showcard = true, -- shows the "Keyless Mode" card autoconfirm = false, -- true: runs the Callback automatically when the UI opens }, -- Notification style NotifStyle = "1", -- Tabs style: "1" = Tabs in a column on the left, "2" = Tabs in a row under the topbar TabsStyle = "1", -- Games SupportedGames = {}, -- Script Execution Callback = function(key) -- your script here end, } end local KeySystem = {} function KeySystem.new(options) return import("components/window/ui").new(options) end -- Works as KeySystem:SetGetkeyTitle("...") or KeySystem.SetGetkeyTitle("...") local function firstArg(a, b) if a == KeySystem then return b end return a end function KeySystem.SetGetkeyTitle(a, b) import("components/window/ui").SetGetkeyTitle(firstArg(a, b)) return KeySystem end function KeySystem.SetGetkeyIcon(a, b) import("components/window/ui").SetGetkeyIcon(firstArg(a, b)) return KeySystem end -- Works as KeySystem:SetNotifStyle("3") / KeySystem:NotifStyle("3") function KeySystem.SetNotifStyle(a, b) import("components/window/ui").SetNotifStyle(firstArg(a, b)) return KeySystem end KeySystem.NotifStyle = KeySystem.SetNotifStyle -- Works as KeySystem:SetTabsStyle("2") / KeySystem.SetTabsStyle("2") ("1": Tabs on the left, -- "2": Tabs in a row under the topbar), before or after KeySystem.new(...). function KeySystem.SetTabsStyle(a, b) import("components/window/ui").SetTabsStyle(firstArg(a, b)) return KeySystem end KeySystem.TabsStyle = KeySystem.SetTabsStyle -- Works as KeySystem:GetMethod({...}) / KeySystem.GetMethod({...}), same as the -- other Set* helpers above: usable standalone, before KeySystem.new(...) exists. function KeySystem.GetMethod(a, b) return import("components/window/ui").GetMethod(firstArg(a, b)) end -- Works as KeySystem:SetUIFont("...") / KeySystem.SetUIFont("...") function KeySystem.SetUIFont(a, b) import("components/window/ui").SetUIFont(firstArg(a, b)) return KeySystem end -- Works as KeySystem:SetTitleFont("...") / KeySystem.SetTitleFont("...") function KeySystem.SetTitleFont(a, b) import("components/window/ui").SetTitleFont(firstArg(a, b)) return KeySystem end KeySystem.Jnkie = import("utilities/jnkie") KeySystem.UnoAuth = import("utilities/unoauth") return KeySystem