Skip to content

Hub #48

Description

@Txzp

--[[
NoirX Tz — UI Library
Fluent Dark | Sidebar Layout
by Tz (base: Rayfield open source)

API compatible con Rayfield:
  local Window = NoirX:CreateWindow({...})
  local Tab    = Window:CreateTab("Name", iconId)
  Tab:CreateButton / Toggle / Slider / Dropdown / Input / Keybind / ColorPicker / Label / Paragraph / Section
  NoirX:Notify({Title, Content, Duration, Image})
  NoirX:Destroy()

]]

-- ============================================================
-- SERVICES
-- ============================================================
local UIS = game:GetService("UserInputService")
local TweenSvc = game:GetService("TweenService")
local HttpSvc = game:GetService("HttpService")
local RunSvc = game:GetService("RunService")
local Players = game:GetService("Players")
local CoreGui = game:GetService("CoreGui")

local LocalPlayer = Players.LocalPlayer

-- ============================================================
-- CONFIG & SAVE
-- ============================================================
local FOLDER = "NoirX"
local CFG_FOLDER = FOLDER .. "/Configurations"
local CFG_EXT = ".nxcfg"

local function safeMakeFolder(path)
pcall(function()
if not isfolder(path) then makefolder(path) end
end)
end
safeMakeFolder(FOLDER)
safeMakeFolder(CFG_FOLDER)

-- ============================================================
-- THEME (Fluent Dark / Noir)
-- ============================================================
local T = {
-- base
BG = Color3.fromRGB(18, 18, 22 ), -- ventana
BGDeep = Color3.fromRGB(12, 12, 15 ), -- sidebar
Surface = Color3.fromRGB(28, 28, 34 ), -- elementos
SurfaceHi = Color3.fromRGB(36, 36, 44 ), -- hover
-- accent
Accent = Color3.fromRGB(0, 120, 212), -- azul fluent
AccentDim = Color3.fromRGB(0, 80, 150),
AccentGlow = Color3.fromRGB(30, 140, 240),
-- texto
Text = Color3.fromRGB(230, 230, 235),
TextDim = Color3.fromRGB(130, 130, 145),
TextDisabled= Color3.fromRGB(70, 70, 80 ),
-- bordes
Border = Color3.fromRGB(45, 45, 55 ),
BorderHi = Color3.fromRGB(65, 65, 80 ),
-- estados
Success = Color3.fromRGB(20, 200, 100),
Error = Color3.fromRGB(200, 50, 50 ),
Warning = Color3.fromRGB(220, 170, 30 ),
-- toggle
ToggleBG = Color3.fromRGB(25, 25, 32 ),
ToggleOn = Color3.fromRGB(0, 120, 212),
ToggleOff = Color3.fromRGB(80, 80, 95 ),
-- slider
SliderBG = Color3.fromRGB(30, 30, 38 ),
SliderFill = Color3.fromRGB(0, 120, 212),
-- sidebar
SidebarW = 160,
-- misc
White = Color3.fromRGB(255, 255, 255),
Black = Color3.fromRGB(0, 0, 0 ),
}

-- ============================================================
-- TWEEN HELPERS
-- ============================================================
local function tw(obj, t, props)
TweenSvc:Create(obj, TweenInfo.new(t, Enum.EasingStyle.Quint, Enum.EasingDirection.Out), props):Play()
end
local function twIn(obj, t, props)
TweenSvc:Create(obj, TweenInfo.new(t, Enum.EasingStyle.Quint, Enum.EasingDirection.In), props):Play()
end

-- ============================================================
-- INSTANCE HELPERS
-- ============================================================
local function New(cls, props, parent)
local o = Instance.new(cls)
for k, v in pairs(props or {}) do o[k] = v end
if parent then o.Parent = parent end
return o
end
local function Corner(r, p) return New("UICorner",{CornerRadius=UDim.new(0,r)},p) end
local function Stroke(c,th,p) local s=New("UIStroke",{Color=c,Thickness=th or 0.8},p); return s end
local function Pad(l,r,t,b,p) return New("UIPadding",{PaddingLeft=UDim.new(0,l),PaddingRight=UDim.new(0,r),PaddingTop=UDim.new(0,t),PaddingBottom=UDim.new(0,b)},p) end
local function ListLayout(p,sp,dir)
return New("UIListLayout",{SortOrder=Enum.SortOrder.LayoutOrder,Padding=UDim.new(0,sp or 6),FillDirection=dir or Enum.FillDirection.Vertical},p)
end

-- ============================================================
-- LIBRARY TABLE
-- ============================================================
local NoirX = { Flags = {} }

-- ============================================================
-- ROOT GUI
-- ============================================================
for _, v in ipairs(CoreGui:GetChildren()) do
if v.Name == "NoirX_Tz" then v:Destroy() end
end
local Root = New("ScreenGui", {
Name = "NoirX_Tz",
ResetOnSpawn = false,
ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
IgnoreGuiInset = true,
}, CoreGui)

-- Notifications container
local NotifContainer = New("Frame", {
Size = UDim2.new(0, 310, 1, 0),
Position = UDim2.new(1, -320, 0, 0),
BackgroundTransparency = 1,
ZIndex = 200,
}, Root)
ListLayout(NotifContainer, 8)
Pad(0,0,12,12,NotifContainer)

-- ============================================================
-- NOTIFY
-- ============================================================
function NoirX:Notify(cfg)
task.spawn(function()
local dur = cfg.Duration or 5
local notif = New("Frame", {
Size = UDim2.new(1, 0, 0, 0),
BackgroundColor3 = T.Surface,
BackgroundTransparency = 1,
ClipsDescendants = true,
ZIndex = 200,
}, NotifContainer)
Corner(10, notif)
Stroke(T.BorderHi, 0.7, notif)

    local icon = New("ImageLabel", {
        Size                    = UDim2.new(0, 20, 0, 20),
        Position                = UDim2.new(0, 12, 0, 14),
        BackgroundTransparency  = 1,
        Image                   = cfg.Image and ("rbxassetid://"..tostring(cfg.Image)) or "rbxassetid://3944680095",
        ImageColor3             = T.Accent,
        ZIndex                  = 201,
    }, notif)

    local title = New("TextLabel", {
        Size                    = UDim2.new(1, -48, 0, 18),
        Position                = UDim2.new(0, 40, 0, 10),
        BackgroundTransparency  = 1,
        Text                    = cfg.Title or "Notification",
        TextColor3              = T.Text,
        TextSize                = 12,
        Font                    = Enum.Font.GothamBold,
        TextXAlignment          = Enum.TextXAlignment.Left,
        TextTransparency        = 1,
        ZIndex                  = 201,
    }, notif)

    local content = New("TextLabel", {
        Size                    = UDim2.new(1, -24, 0, 30),
        Position                = UDim2.new(0, 12, 0, 32),
        BackgroundTransparency  = 1,
        Text                    = cfg.Content or "",
        TextColor3              = T.TextDim,
        TextSize                = 11,
        Font                    = Enum.Font.Gotham,
        TextXAlignment          = Enum.TextXAlignment.Left,
        TextWrapped             = true,
        TextTransparency        = 1,
        ZIndex                  = 201,
    }, notif)

    -- progress bar
    local bar = New("Frame", {
        Size                    = UDim2.new(1, 0, 0, 2),
        Position                = UDim2.new(0, 0, 1, -2),
        BackgroundColor3        = T.Accent,
        BorderSizePixel         = 0,
        ZIndex                  = 202,
    }, notif)

    tw(notif, 0.3, {BackgroundTransparency = 0.08, Size = UDim2.new(1, 0, 0, 72)})
    tw(title, 0.4, {TextTransparency = 0})
    tw(content, 0.4, {TextTransparency = 0.2})
    tw(bar, dur, {Size = UDim2.new(0, 0, 0, 2)})

    task.wait(dur)
    tw(notif, 0.3, {BackgroundTransparency = 1, Size = UDim2.new(1, 0, 0, 0)})
    task.wait(0.35)
    notif:Destroy()
end)

end

-- ============================================================
-- SAVE / LOAD HELPERS
-- ============================================================
local CFileName = nil
local CEnabled = false

local function SaveConfig()
if not CEnabled then return end
local data = {}
for k, v in pairs(NoirX.Flags) do
if v.Type == "ColorPicker" then
data[k] = {R = v.Color.R255, G = v.Color.G255, B = v.Color.B*255}
else
data[k] = v.CurrentValue or v.CurrentKeybind or v.CurrentOption or v.Color
end
end
pcall(writefile, CFG_FOLDER.."/"..CFileName..CFG_EXT, HttpSvc:JSONEncode(data))
end

local function LoadConfig()
if not CEnabled then return end
pcall(function()
local path = CFG_FOLDER.."/"..CFileName..CFG_EXT
if not isfile(path) then return end
local data = HttpSvc:JSONDecode(readfile(path))
for k, v in pairs(data) do
if NoirX.Flags[k] then
task.spawn(function()
local f = NoirX.Flags[k]
if f.Type == "ColorPicker" then
f:Set(Color3.fromRGB(v.R, v.G, v.B))
else
if f.CurrentValue ~= v or f.CurrentKeybind ~= v or f.CurrentOption ~= v then
f:Set(v)
end
end
end)
end
end
NoirX:Notify({Title = "Config Loaded", Content = "Settings restored from last session.", Duration = 4})
end)
end

-- ============================================================
-- CREATE WINDOW
-- ============================================================
function NoirX:CreateWindow(cfg)
cfg = cfg or {}
local WIN_W = 640
local WIN_H = 460
local SIDE_W = T.SidebarW

-- ---- CONFIG SAVING ----
pcall(function()
    if cfg.ConfigurationSaving then
        CFileName = cfg.ConfigurationSaving.FileName or tostring(game.PlaceId)
        CEnabled  = cfg.ConfigurationSaving.Enabled ~= false
        if CEnabled then safeMakeFolder(cfg.ConfigurationSaving.FolderName or CFG_FOLDER) end
    end
end)

-- ============================================================
-- KEY SYSTEM
-- ============================================================
if cfg.KeySystem and cfg.KeySettings then
    local KS = cfg.KeySettings
    if typeof(KS.Key) == "string" then KS.Key = {KS.Key} end

    if KS.GrabKeyFromSite then
        for i, k in ipairs(KS.Key) do
            pcall(function()
                KS.Key[i] = tostring(game:HttpGet(k)):gsub("[\n\r ]","")
            end)
        end
    end

    KS.FileName = KS.FileName or "NoirX_Key"
    local keyPath = FOLDER.."/Key System"
    safeMakeFolder(keyPath)

    local passthrough = false
    pcall(function()
        local saved = readfile(keyPath.."/"..KS.FileName..CFG_EXT)
        for _, mk in ipairs(KS.Key) do
            if saved:find(mk, 1, true) then passthrough = true end
        end
    end)

    if not passthrough then
        -- Key UI
        local KeyRoot = New("ScreenGui",{Name="NoirX_Key",ResetOnSpawn=false,IgnoreGuiInset=true,ZIndexBehavior=Enum.ZIndexBehavior.Sibling},CoreGui)
        local kBG = New("Frame",{
            Size=UDim2.new(0,440,0,220),
            Position=UDim2.new(0.5,-220,0.5,-110),
            BackgroundColor3=T.BG,
            BackgroundTransparency=0,
            BorderSizePixel=0,
        },KeyRoot)
        Corner(14,kBG)
        Stroke(T.BorderHi,0.8,kBG)

        -- accent bar top
        New("Frame",{Size=UDim2.new(1,0,0,3),BackgroundColor3=T.Accent,BorderSizePixel=0},kBG)
        Corner(14, kBG:FindFirstChildOfClass("Frame"))

        New("TextLabel",{
            Size=UDim2.new(1,0,0,28),Position=UDim2.new(0,0,0,14),
            BackgroundTransparency=1,Text=KS.Title or cfg.Name or "NoirX Tz",
            TextColor3=T.Text,TextSize=16,Font=Enum.Font.GothamBold,
            TextXAlignment=Enum.TextXAlignment.Center,
        },kBG)
        New("TextLabel",{
            Size=UDim2.new(1,0,0,20),Position=UDim2.new(0,0,0,42),
            BackgroundTransparency=1,Text=KS.Subtitle or "Key System",
            TextColor3=T.TextDim,TextSize=11,Font=Enum.Font.Gotham,
            TextXAlignment=Enum.TextXAlignment.Center,
        },kBG)
        New("TextLabel",{
            Size=UDim2.new(1,-40,0,16),Position=UDim2.new(0,20,0,70),
            BackgroundTransparency=1,Text=KS.Note or "Enter the key below.",
            TextColor3=T.TextDim,TextSize=10,Font=Enum.Font.Gotham,
            TextXAlignment=Enum.TextXAlignment.Center,TextWrapped=true,
        },kBG)

        local kInput = New("TextBox",{
            Size=UDim2.new(1,-40,0,36),Position=UDim2.new(0,20,0,100),
            BackgroundColor3=T.Surface,BorderSizePixel=0,
            PlaceholderText="paste key here...",PlaceholderColor3=T.TextDim,
            Text="",TextColor3=T.Text,TextSize=12,Font=Enum.Font.Gotham,
            ClearTextOnFocus=false,
        },kBG)
        Corner(8,kInput)
        Stroke(T.BorderHi,0.7,kInput)
        Pad(10,10,0,0,kInput)

        local kStatus = New("TextLabel",{
            Size=UDim2.new(1,-40,0,16),Position=UDim2.new(0,20,0,148),
            BackgroundTransparency=1,Text="",
            TextColor3=T.Error,TextSize=10,Font=Enum.Font.Gotham,
            TextXAlignment=Enum.TextXAlignment.Center,
        },kBG)

        local kBtn = New("TextButton",{
            Size=UDim2.new(1,-40,0,36),Position=UDim2.new(0,20,0,172),
            BackgroundColor3=T.Accent,BorderSizePixel=0,
            Text="UNLOCK",TextColor3=T.White,TextSize=12,Font=Enum.Font.GothamBold,
        },kBG)
        Corner(8,kBtn)

        local attempts = 5
        kBtn.MouseButton1Click:Connect(function()
            local found = false
            local foundKey = ""
            for _, mk in ipairs(KS.Key) do
                if kInput.Text:find(mk, 1, true) then
                    found = true; foundKey = mk
                end
            end
            if found then
                if KS.SaveKey then
                    pcall(writefile, keyPath.."/"..KS.FileName..CFG_EXT, foundKey)
                end
                tw(kBG, 0.3, {BackgroundTransparency=1})
                task.wait(0.35)
                KeyRoot:Destroy()
                passthrough = true
            else
                attempts = attempts - 1
                if attempts <= 0 then
                    LocalPlayer:Kick("NoirX: No attempts remaining.")
                end
                kStatus.Text = "Invalid key. "..attempts.." attempt(s) left."
                tw(kInput, 0.1, {BackgroundColor3=Color3.fromRGB(80,20,20)})
                task.wait(0.5)
                tw(kInput, 0.3, {BackgroundColor3=T.Surface})
            end
        end)

        repeat task.wait() until passthrough
    end
end

-- ============================================================
-- MAIN WINDOW FRAME
-- ============================================================
local Main = New("Frame",{
    Name            = "NoirX_Main",
    Size            = UDim2.new(0, WIN_W, 0, WIN_H),
    Position        = UDim2.new(0.5, -WIN_W/2, 0.5, -WIN_H/2),
    BackgroundColor3= T.BG,
    BorderSizePixel = 0,
    ClipsDescendants= false,
}, Root)
Corner(14, Main)
Stroke(T.Border, 0.8, Main)

-- shadow
New("ImageLabel",{
    Size=UDim2.new(1,40,1,40),Position=UDim2.new(0,-20,0,-20),
    BackgroundTransparency=1,
    Image="rbxassetid://5028857084",
    ImageColor3=T.Black,ImageTransparency=0.6,
    ZIndex=0,ScaleType=Enum.ScaleType.Slice,SliceCenter=Rect.new(24,24,276,276),
},Main)

-- accent line top
local accentBar = New("Frame",{
    Size=UDim2.new(1,0,0,2),
    BackgroundColor3=T.Accent,
    BorderSizePixel=0,
    ZIndex=10,
},Main)
Corner(14,accentBar)

-- ============================================================
-- DRAG
-- ============================================================
do
    local dragging, dragStart, startPos = false
    Main.InputBegan:Connect(function(i)
        if i.UserInputType == Enum.UserInputType.MouseButton1 then
            dragging=true; dragStart=i.Position; startPos=Main.Position
        end
    end)
    Main.InputEnded:Connect(function(i)
        if i.UserInputType == Enum.UserInputType.MouseButton1 then dragging=false end
    end)
    UIS.InputChanged:Connect(function(i)
        if dragging and i.UserInputType==Enum.UserInputType.MouseMovement then
            local d = i.Position - dragStart
            tw(Main, 0.12, {Position=UDim2.new(startPos.X.Scale,startPos.X.Offset+d.X,startPos.Y.Scale,startPos.Y.Offset+d.Y)})
        end
    end)
end

-- ============================================================
-- SIDEBAR
-- ============================================================
local Sidebar = New("Frame",{
    Size            = UDim2.new(0, SIDE_W, 1, 0),
    BackgroundColor3= T.BGDeep,
    BorderSizePixel = 0,
    ZIndex          = 5,
    ClipsDescendants= true,
}, Main)
Corner(14, Sidebar)
-- fix right corners
New("Frame",{
    Size=UDim2.new(0,14,1,0),Position=UDim2.new(1,-14,0,0),
    BackgroundColor3=T.BGDeep,BorderSizePixel=0,ZIndex=5,
},Sidebar)

-- logo / title area
local SideTop = New("Frame",{
    Size=UDim2.new(1,0,0,56),
    BackgroundTransparency=1,
    ZIndex=6,
},Sidebar)
New("TextLabel",{
    Size=UDim2.new(1,-16,0,20),Position=UDim2.new(0,12,0,10),
    BackgroundTransparency=1,
    Text="NoirX Tz",
    TextColor3=T.Text,TextSize=13,Font=Enum.Font.GothamBold,
    TextXAlignment=Enum.TextXAlignment.Left,ZIndex=7,
},SideTop)
New("TextLabel",{
    Size=UDim2.new(1,-16,0,14),Position=UDim2.new(0,12,0,30),
    BackgroundTransparency=1,
    Text=cfg.Name or "Script Hub",
    TextColor3=T.TextDim,TextSize=9,Font=Enum.Font.Gotham,
    TextXAlignment=Enum.TextXAlignment.Left,ZIndex=7,
},SideTop)

-- divider
New("Frame",{
    Size=UDim2.new(1,-24,0,1),Position=UDim2.new(0,12,0,56),
    BackgroundColor3=T.Border,BorderSizePixel=0,ZIndex=6,
},Sidebar)

-- tab buttons list
local TabBtnList = New("ScrollingFrame",{
    Size=UDim2.new(1,0,1,-64),Position=UDim2.new(0,0,0,62),
    BackgroundTransparency=1,BorderSizePixel=0,
    ScrollBarThickness=0,CanvasSize=UDim2.new(0,0,0,0),
    AutomaticCanvasSize=Enum.AutomaticSize.Y,
    ZIndex=6,
},Sidebar)
ListLayout(TabBtnList, 4)
Pad(8,8,6,6,TabBtnList)

-- ============================================================
-- CONTENT AREA
-- ============================================================
local ContentArea = New("Frame",{
    Size            = UDim2.new(1,-SIDE_W,1,0),
    Position        = UDim2.new(0,SIDE_W,0,0),
    BackgroundTransparency=1,
    ZIndex          = 5,
    ClipsDescendants= true,
}, Main)

-- topbar
local Topbar = New("Frame",{
    Size=UDim2.new(1,0,0,44),
    BackgroundTransparency=1,
    ZIndex=6,
},ContentArea)

local WinTitle = New("TextLabel",{
    Size=UDim2.new(1,-80,1,0),Position=UDim2.new(0,16,0,0),
    BackgroundTransparency=1,
    Text=cfg.Name or "NoirX",
    TextColor3=T.Text,TextSize=13,Font=Enum.Font.GothamBold,
    TextXAlignment=Enum.TextXAlignment.Left,ZIndex=7,
},Topbar)

-- close / minimise buttons
local function mkTopBtn(xOff, color, symbol, cb)
    local b = New("TextButton",{
        Size=UDim2.new(0,22,0,22),
        Position=UDim2.new(1,-xOff,0.5,-11),
        BackgroundColor3=color,
        BorderSizePixel=0,
        Text=symbol,TextColor3=T.White,TextSize=10,Font=Enum.Font.GothamBold,
        ZIndex=8,
    },Topbar)
    Corner(11,b)
    b.MouseEnter:Connect(function() tw(b,0.1,{BackgroundColor3=color:Lerp(T.White,0.2)}) end)
    b.MouseLeave:Connect(function() tw(b,0.1,{BackgroundColor3=color}) end)
    b.MouseButton1Click:Connect(cb)
    return b
end

local minimised = false
local hidden    = false

mkTopBtn(28, T.Error, "×", function()
    tw(Main,0.25,{Size=UDim2.new(0,WIN_W,0,1),BackgroundTransparency=1})
    task.wait(0.28)
    Root:Destroy()
end)
local minBtn = mkTopBtn(56, T.Warning, "–", function()
    if minimised then
        minimised = false
        tw(Main,0.3,{Size=UDim2.new(0,WIN_W,0,WIN_H)})
        ContentArea.Visible = true
    else
        minimised = true
        ContentArea.Visible = false
        tw(Main,0.3,{Size=UDim2.new(0,WIN_W,0,44)})
    end
end)

-- topbar divider
New("Frame",{
    Size=UDim2.new(1,0,0,1),Position=UDim2.new(0,0,1,-1),
    BackgroundColor3=T.Border,BorderSizePixel=0,ZIndex=6,
},Topbar)

-- page container
local Pages = New("Frame",{
    Size=UDim2.new(1,0,1,-44),Position=UDim2.new(0,0,0,44),
    BackgroundTransparency=1,ClipsDescendants=true,ZIndex=5,
},ContentArea)

-- ============================================================
-- KEYBIND HIDE  (K)
-- ============================================================
UIS.InputBegan:Connect(function(input, processed)
    if processed then return end
    if UIS:GetFocusedTextBox() then return end
    if input.KeyCode == Enum.KeyCode.K then
        if hidden then
            hidden = false
            Main.Visible = true
            tw(Main,0.3,{BackgroundTransparency=0})
            NoirX:Notify({Title="Interface Shown", Content="Press K to hide again.", Duration=3})
        else
            hidden = true
            NoirX:Notify({Title="Interface Hidden", Content="Press K to show again.", Duration=3})
            task.wait(0.1)
            tw(Main,0.2,{BackgroundTransparency=1})
            task.wait(0.25)
            Main.Visible = false
        end
    end
end)

-- ============================================================
-- WINDOW OBJECT
-- ============================================================
local Window = {}
local firstTab    = true
local currentPage = nil

-- ============================================================
-- CREATE TAB
-- ============================================================
function Window:CreateTab(name, image)
    -- Page
    local Page = New("ScrollingFrame",{
        Name=name,
        Size=UDim2.new(1,-10,1,-10),Position=UDim2.new(0,5,0,5),
        BackgroundTransparency=1,BorderSizePixel=0,
        ScrollBarThickness=2,ScrollBarImageColor3=T.TextDim,
        CanvasSize=UDim2.new(0,0,0,0),AutomaticCanvasSize=Enum.AutomaticSize.Y,
        Visible=false,ZIndex=6,
    },Pages)
    ListLayout(Page, 6)
    Pad(8,8,6,8,Page)

    -- Sidebar Button
    local TabBtn = New("TextButton",{
        Name=name,
        Size=UDim2.new(1,0,0,34),
        BackgroundColor3=T.Surface,
        BackgroundTransparency=1,
        BorderSizePixel=0,
        Text="",
        ZIndex=7,
    },TabBtnList)
    Corner(8,TabBtn)

    local tabIcon = New("ImageLabel",{
        Size=UDim2.new(0,16,0,16),
        Position=UDim2.new(0,10,0.5,-8),
        BackgroundTransparency=1,
        Image=image and ("rbxassetid://"..tostring(image)) or "rbxassetid://3926305904",
        ImageColor3=T.TextDim,ZIndex=8,
    },TabBtn)

    local tabLbl = New("TextLabel",{
        Size=UDim2.new(1,-36,1,0),
        Position=UDim2.new(0,32,0,0),
        BackgroundTransparency=1,
        Text=name,
        TextColor3=T.TextDim,TextSize=11,Font=Enum.Font.Gotham,
        TextXAlignment=Enum.TextXAlignment.Left,ZIndex=8,
    },TabBtn)

    -- indicator
    local indicator = New("Frame",{
        Size=UDim2.new(0,3,0.6,0),
        Position=UDim2.new(0,-2,0.2,0),
        BackgroundColor3=T.Accent,
        BorderSizePixel=0,
        BackgroundTransparency=1,
        ZIndex=9,
    },TabBtn)
    Corner(3,indicator)

    local function selectTab()
        -- hide all
        for _, p in ipairs(Pages:GetChildren()) do
            if p:IsA("ScrollingFrame") then p.Visible = false end
        end
        -- deselect all btns
        for _, b in ipairs(TabBtnList:GetChildren()) do
            if b:IsA("TextButton") then
                tw(b, 0.2, {BackgroundTransparency=1})
                local ic = b:FindFirstChildOfClass("ImageLabel")
                local lb = b:FindFirstChildOfClass("TextLabel")
                local ind= b:FindFirstChildOfClass("Frame")
                if ic then tw(ic,0.2,{ImageColor3=T.TextDim}) end
                if lb then tw(lb,0.2,{TextColor3=T.TextDim, Font=Enum.Font.Gotham}) end
                if ind then tw(ind,0.2,{BackgroundTransparency=1}) end
            end
        end
        -- select this
        Page.Visible = true
        tw(TabBtn,0.2,{BackgroundTransparency=0.7,BackgroundColor3=T.AccentDim})
        tw(tabIcon,0.2,{ImageColor3=T.White})
        tw(tabLbl,0.2,{TextColor3=T.White})
        tabLbl.Font = Enum.Font.GothamBold
        tw(indicator,0.2,{BackgroundTransparency=0})
        currentPage = Page
    end

    TabBtn.MouseButton1Click:Connect(selectTab)
    TabBtn.MouseEnter:Connect(function()
        if Page.Visible then return end
        tw(TabBtn,0.15,{BackgroundTransparency=0.85})
    end)
    TabBtn.MouseLeave:Connect(function()
        if Page.Visible then return end
        tw(TabBtn,0.15,{BackgroundTransparency=1})
    end)

    if firstTab then
        firstTab = false
        selectTab()
    end

    -- ============================================================
    -- ELEMENT HELPERS (internos)
    -- ============================================================
    local function mkElement(h)
        h = h or 40
        local el = New("Frame",{
            Size=UDim2.new(1,0,0,h),
            BackgroundColor3=T.Surface,
            BorderSizePixel=0,
            ZIndex=7,
        },Page)
        Corner(8,el)
        Stroke(T.Border,0.6,el)
        return el
    end

    local function mkTitle(parent, text, xOff, w)
        return New("TextLabel",{
            Size=UDim2.new(w or 0.55,-(xOff or 14),1,0),
            Position=UDim2.new(0,xOff or 14,0,0),
            BackgroundTransparency=1,
            Text=text,TextColor3=T.Text,TextSize=11,
            Font=Enum.Font.Gotham,TextXAlignment=Enum.TextXAlignment.Left,
            ZIndex=8,
        },parent)
    end

    local function hoverEl(el)
        el.MouseEnter:Connect(function() tw(el,0.15,{BackgroundColor3=T.SurfaceHi}) end)
        el.MouseLeave:Connect(function() tw(el,0.15,{BackgroundColor3=T.Surface}) end)
    end

    -- ============================================================
    -- TAB OBJECT
    -- ============================================================
    local Tab = {}

    -- ---- SECTION ----
    function Tab:CreateSection(sname)
        local sec = New("Frame",{
            Size=UDim2.new(1,0,0,22),
            BackgroundTransparency=1,ZIndex=7,
        },Page)
        New("TextLabel",{
            Size=UDim2.new(1,-14,1,0),Position=UDim2.new(0,14,0,0),
            BackgroundTransparency=1,Text=sname:upper(),
            TextColor3=T.Accent,TextSize=9,Font=Enum.Font.GothamBold,
            TextXAlignment=Enum.TextXAlignment.Left,ZIndex=8,
        },sec)
        -- line
        New("Frame",{
            Size=UDim2.new(1,-14,0,1),Position=UDim2.new(0,14,1,-1),
            BackgroundColor3=T.AccentDim,BorderSizePixel=0,ZIndex=8,
        },sec)
        local sv = {}
        function sv:Set(t) sec:FindFirstChildOfClass("TextLabel").Text = t:upper() end
        return sv
    end

    -- ---- LABEL ----
    function Tab:CreateLabel(text)
        local el = New("Frame",{
            Size=UDim2.new(1,0,0,32),
            BackgroundColor3=T.BGDeep,BorderSizePixel=0,ZIndex=7,
        },Page)
        Corner(8,el)
        Stroke(T.Border,0.5,el)
        local lbl = New("TextLabel",{
            Size=UDim2.new(1,-28,1,0),Position=UDim2.new(0,14,0,0),
            BackgroundTransparency=1,Text=text,TextColor3=T.TextDim,
            TextSize=11,Font=Enum.Font.Gotham,TextXAlignment=Enum.TextXAlignment.Left,
            ZIndex=8,TextWrapped=true,
        },el)
        local lv = {}
        function lv:Set(t) lbl.Text=t end
        return lv
    end

    -- ---- PARAGRAPH ----
    function Tab:CreateParagraph(s)
        local lines = math.max(1, math.ceil(#(s.Content or "") / 55))
        local h = 36 + lines*14
        local el = New("Frame",{
            Size=UDim2.new(1,0,0,h),
            BackgroundColor3=T.BGDeep,BorderSizePixel=0,ZIndex=7,
        },Page)
        Corner(8,el)
        Stroke(T.Border,0.5,el)
        New("TextLabel",{
            Size=UDim2.new(1,-28,0,16),Position=UDim2.new(0,14,0,8),
            BackgroundTransparency=1,Text=s.Title or "",
            TextColor3=T.Text,TextSize=11,Font=Enum.Font.GothamBold,
            TextXAlignment=Enum.TextXAlignment.Left,ZIndex=8,
        },el)
        New("TextLabel",{
            Size=UDim2.new(1,-28,1,-28),Position=UDim2.new(0,14,0,26),
            BackgroundTransparency=1,Text=s.Content or "",
            TextColor3=T.TextDim,TextSize=10,Font=Enum.Font.Gotham,
            TextXAlignment=Enum.TextXAlignment.Left,TextWrapped=true,ZIndex=8,
        },el)
        local pv = {}
        function pv:Set(ns)
            el:FindFirstChild("TextLabel").Text = ns.Title or ""
            local all = el:GetChildren()
            if all[2] then all[2].Text = ns.Content or "" end
        end
        return pv
    end

    -- ---- BUTTON ----
    function Tab:CreateButton(s)
        local el = mkElement(40)
        hoverEl(el)
        mkTitle(el, s.Name)

        -- reveal highlight
        local revealBtn = New("TextButton",{
            Size=UDim2.new(0,90,0,26),
            Position=UDim2.new(1,-100,0.5,-13),
            BackgroundColor3=T.Accent,BorderSizePixel=0,
            Text="Run",TextColor3=T.White,TextSize=10,Font=Enum.Font.GothamBold,
            ZIndex=9,
        },el)
        Corner(7,revealBtn)
        revealBtn.MouseEnter:Connect(function() tw(revealBtn,0.1,{BackgroundColor3=T.AccentGlow}) end)
        revealBtn.MouseLeave:Connect(function() tw(revealBtn,0.1,{BackgroundColor3=T.Accent}) end)
        revealBtn.MouseButton1Click:Connect(function()
            tw(revealBtn,0.1,{BackgroundColor3=T.White})
            task.spawn(function()
                local ok,err=pcall(s.Callback)
                if not ok then
                    tw(el,0.3,{BackgroundColor3=Color3.fromRGB(60,15,15)})
                    task.wait(0.6)
                    tw(el,0.3,{BackgroundColor3=T.Surface})
                else
                    SaveConfig()
                end
            end)
            task.wait(0.1)
            tw(revealBtn,0.2,{BackgroundColor3=T.Accent})
        end)

        local bv = {}
        function bv:Set(t) el:FindFirstChildOfClass("TextLabel").Text=t end
        return bv
    end

    -- ---- TOGGLE ----
    function Tab:CreateToggle(s)
        local el = mkElement(40)
        hoverEl(el)
        mkTitle(el, s.Name)

        local track = New("Frame",{
            Size=UDim2.new(0,42,0,22),
            Position=UDim2.new(1,-56,0.5,-11),
            BackgroundColor3=s.CurrentValue and T.ToggleOn or T.ToggleOff,
            BorderSizePixel=0,ZIndex=9,
        },el)
        Corner(11,track)

        local thumb = New("Frame",{
            Size=UDim2.new(0,16,0,16),
            Position=s.CurrentValue and UDim2.new(1,-19,0.5,-8) or UDim2.new(0,3,0.5,-8),
            BackgroundColor3=T.White,BorderSizePixel=0,ZIndex=10,
        },track)
        Corner(8,thumb)

        local interact = New("TextButton",{
            Size=UDim2.new(1,0,1,0),BackgroundTransparency=1,Text="",ZIndex=11,
        },track)

        interact.MouseButton1Click:Connect(function()
            s.CurrentValue = not s.CurrentValue
            if s.CurrentValue then
                tw(track,0.25,{BackgroundColor3=T.ToggleOn})
                tw(thumb,0.25,{Position=UDim2.new(1,-19,0.5,-8)})
            else
                tw(track,0.25,{BackgroundColor3=T.ToggleOff})
                tw(thumb,0.25,{Position=UDim2.new(0,3,0.5,-8)})
            end
            task.spawn(function() pcall(s.Callback, s.CurrentValue) end)
            SaveConfig()
        end)

        if s.Flag then NoirX.Flags[s.Flag] = s end
        local tv = {}
        tv.Type = "Toggle"
        function tv:Set(val)
            s.CurrentValue = val
            if val then
                tw(track,0.25,{BackgroundColor3=T.ToggleOn})
                tw(thumb,0.25,{Position=UDim2.new(1,-19,0.5,-8)})
            else
                tw(track,0.25,{BackgroundColor3=T.ToggleOff})
                tw(thumb,0.25,{Position=UDim2.new(0,3,0.5,-8)})
            end
            task.spawn(function() pcall(s.Callback, s.CurrentValue) end)
        end
        s.Set = tv.Set
        return s
    end

    -- ---- SLIDER ----
    function Tab:CreateSlider(s)
        local el = mkElement(52)
        hoverEl(el)
        mkTitle(el, s.Name, 14, 0.5)

        local valLbl = New("TextLabel",{
            Size=UDim2.new(0,60,0,16),
            Position=UDim2.new(1,-70,0,4),
            BackgroundTransparency=1,
            Text=tostring(s.CurrentValue)..(s.Suffix and (" "..s.Suffix) or ""),
            TextColor3=T.Accent,TextSize=10,Font=Enum.Font.GothamBold,
            TextXAlignment=Enum.TextXAlignment.Right,ZIndex=9,
        },el)

        local track = New("Frame",{
            Size=UDim2.new(1,-28,0,6),
            Position=UDim2.new(0,14,0,32),
            BackgroundColor3=T.SliderBG,BorderSizePixel=0,ZIndex=9,
        },el)
        Corner(3,track)

        local fill = New("Frame",{
            Size=UDim2.new(
                math.clamp((s.CurrentValue-s.Range[1])/(s.Range[2]-s.Range[1]),0,1),
                0,1,0),
            BackgroundColor3=T.SliderFill,BorderSizePixel=0,ZIndex=10,
        },track)
        Corner(3,fill)

        local handle = New("Frame",{
            Size=UDim2.new(0,14,0,14),
            Position=UDim2.new(
                math.clamp((s.CurrentValue-s.Range[1])/(s.Range[2]-s.Range[1]),0,1),
                -7,0.5,-7),
            BackgroundColor3=T.White,BorderSizePixel=0,ZIndex=11,
        },track)
        Corner(7,handle)

        local dragging = false
        local interact = New("TextButton",{
            Size=UDim2.new(1,0,3,0),Position=UDim2.new(0,0,-1,0),
            BackgroundTransparency=1,Text="",ZIndex=12,
        },track)

        local function updateSlider(mx)
            local rel = math.clamp((mx - track.AbsolutePosition.X)/track.AbsoluteSize.X,0,1)
            local raw = s.Range[1] + rel*(s.Range[2]-s.Range[1])
            local val = math.floor(raw/s.Increment+0.5)*s.Increment
            val = math.clamp(val, s.Range[1], s.Range[2])
            s.CurrentValue = val
            local pct = (val-s.Range[1])/(s.Range[2]-s.Range[1])
            tw(fill,0.08,{Size=UDim2.new(pct,0,1,0)})
            tw(handle,0.08,{Position=UDim2.new(pct,-7,0.5,-7)})
            valLbl.Text = tostring(val)..(s.Suffix and (" "..s.Suffix) or "")
            task.spawn(function() pcall(s.Callback, val) end)
            SaveConfig()
        end

        interact.InputBegan:Connect(function(i)
            if i.UserInputType==Enum.UserInputType.MouseButton1 then dragging=true end
        end)
        UIS.InputEnded:Connect(function(i)
            if i.UserInputType==Enum.UserInputType.MouseButton1 then dragging=false end
        end)
        UIS.InputChanged:Connect(function(i)
            if dragging and i.UserInputType==Enum.UserInputType.MouseMovement then
                updateSlider(UIS:GetMouseLocation().X)
            end
        end)
        interact.MouseButton1Down:Connect(function()
            updateSlider(UIS:GetMouseLocation().X)
        end)

        if s.Flag then NoirX.Flags[s.Flag] = s end
        function s:Set(val)
            s.CurrentValue = math.clamp(val, s.Range[1], s.Range[2])
            local pct=(s.CurrentValue-s.Range[1])/(s.Range[2]-s.Range[1])
            tw(fill,0.2,{Size=UDim2.new(pct,0,1,0)})
            tw(handle,0.2,{Position=UDim2.new(pct,-7,0.5,-7)})
            valLbl.Text=tostring(s.CurrentValue)..(s.Suffix and (" "..s.Suffix) or "")
            task.spawn(function() pcall(s.Callback, s.CurrentValue) end)
        end
        return s
    end

    -- ---- INPUT ----
    function Tab:CreateInput(s)
        local el = mkElement(40)
        hoverEl(el)
        mkTitle(el, s.Name)

        local box = New("TextBox",{
            Size=UDim2.new(0,140,0,26),
            Position=UDim2.new(1,-150,0.5,-13),
            BackgroundColor3=T.BGDeep,BorderSizePixel=0,
            Text="",PlaceholderText=s.PlaceholderText or "...",
            PlaceholderColor3=T.TextDim,TextColor3=T.Text,
            TextSize=11,Font=Enum.Font.Gotham,
            ClearTextOnFocus=false,ZIndex=9,
        },el)
        Corner(7,box)
        Stroke(T.Border,0.6,box)
        Pad(8,8,0,0,box)

        box.FocusLost:Connect(function()
            task.spawn(function() pcall(s.Callback, box.Text) end)
            if s.RemoveTextAfterFocusLost then box.Text="" end
            SaveConfig()
        end)

        local iv = {}
        function iv:Set(t) box.Text=t end
        return iv
    end

    -- ---- DROPDOWN ----
    function Tab:CreateDropdown(s)
        if typeof(s.CurrentOption)=="string" then s.CurrentOption={s.CurrentOption} end
        if not s.MultipleOptions then s.CurrentOption={s.CurrentOption[1]} end

        local function displayText()
            if #s.CurrentOption==0 then return "None"
            elseif #s.CurrentOption==1 then return s.CurrentOption[1]
            else return "Various ("..#s.CurrentOption..")" end
        end

        local el = New("Frame",{
            Size=UDim2.new(1,0,0,40),
            BackgroundColor3=T.Surface,BorderSizePixel=0,ZIndex=7,
            ClipsDescendants=false,
        },Page)
        Corner(8,el)
        Stroke(T.Border,0.6,el)
        hoverEl(el)

        mkTitle(el, s.Name)

        local selLbl = New("TextLabel",{
            Size=UDim2.new(0,120,1,0),Position=UDim2.new(1,-160,0,0),
            BackgroundTransparency=1,Text=displayText(),
            TextColor3=T.TextDim,TextSize=10,Font=Enum.Font.Gotham,
            TextXAlignment=Enum.TextXAlignment.Right,ZIndex=8,
        },el)

        local arrow = New("TextLabel",{
            Size=UDim2.new(0,20,1,0),Position=UDim2.new(1,-26,0,0),
            BackgroundTransparency=1,Text="▾",
            TextColor3=T.TextDim,TextSize=11,ZIndex=8,
            Font=Enum.Font.GothamBold,
        },el)

        -- dropdown panel (parented to Root so it overlaps everything)
        local panel = New("Frame",{
            Size=UDim2.new(0,el.AbsoluteSize.X,0,0),
            BackgroundColor3=T.BGDeep,BorderSizePixel=0,
            Visible=false,ZIndex=50,ClipsDescendants=true,
        },Root)
        Corner(8,panel)
        Stroke(T.BorderHi,0.7,panel)

        local panelList = New("ScrollingFrame",{
            Size=UDim2.new(1,-4,1,0),Position=UDim2.new(0,2,0,0),
            BackgroundTransparency=1,BorderSizePixel=0,
            ScrollBarThickness=2,ScrollBarImageColor3=T.TextDim,
            CanvasSize=UDim2.new(0,0,0,0),AutomaticCanvasSize=Enum.AutomaticSize.Y,
            ZIndex=51,
        },panel)
        ListLayout(panelList,2)
        Pad(4,4,4,4,panelList)

        local function refreshPanel()
            for _, c in ipairs(panelList:GetChildren()) do
                if c:IsA("TextButton") then c:Destroy() end
            end
            for _, opt in ipairs(s.Options) do
                local isSelected = table.find(s.CurrentOption, opt) ~= nil
                local ob = New("TextButton",{
                    Size=UDim2.new(1,0,0,28),
                    BackgroundColor3=isSelected and T.AccentDim or T.Surface,
                    BackgroundTransparency=isSelected and 0 or 0.4,
                    BorderSizePixel=0,
                    Text="  "..opt,TextColor3=isSelected and T.White or T.Text,
                    TextSize=11,Font=Enum.Font.Gotham,
                    TextXAlignment=Enum.TextXAlignment.Left,
                    ZIndex=52,
                },panelList)
                Corner(6,ob)
                ob.MouseEnter:Connect(function()
                    if not table.find(s.CurrentOption,opt) then
                        tw(ob,0.1,{BackgroundTransparency=0,BackgroundColor3=T.SurfaceHi})
                    end
                end)
                ob.MouseLeave:Connect(function()
                    if not table.find(s.CurrentOption,opt) then
                        tw(ob,0.1,{BackgroundTransparency=0.4,BackgroundColor3=T.Surface})
                    end
                end)
                ob.MouseButton1Click:Connect(function()
                    if not s.MultipleOptions then
                        s.CurrentOption = {opt}
                    else
                        local idx = table.find(s.CurrentOption,opt)
                        if idx then table.remove(s.CurrentOption,idx)
                        else table.insert(s.CurrentOption,opt) end
                    end
                    selLbl.Text = displayText()
                    refreshPanel()
                    task.spawn(function() pcall(s.Callback, s.CurrentOption) end)
                    if not s.MultipleOptions then
                        tw(panel,0.15,{Size=UDim2.new(0,el.AbsoluteSize.X,0,0)})
                        task.wait(0.18); panel.Visible=false
                    end
                    SaveConfig()
                end)
            end
        end
        refreshPanel()

        local opened = false
        local interact = New("TextButton",{
            Size=UDim2.new(1,0,1,0),BackgroundTransparency=1,Text="",ZIndex=9,
        },el)

        local function positionPanel()
            local abs = el.AbsolutePosition
            local sz  = el.AbsoluteSize
            local optH= math.min(#s.Options*30+12, 200)
            local screenH = workspace.CurrentCamera.ViewportSize.Y
            local yPos = abs.Y+sz.Y+4
            if yPos+optH > screenH then yPos = abs.Y-optH-4 end
            panel.Position = UDim2.new(0, abs.X, 0, yPos)
            panel.Size = UDim2.new(0, sz.X, 0, 0)
            return optH
        end

        interact.MouseButton1Click:Connect(function()
            if opened then
                opened=false
                tw(panel,0.15,{Size=UDim2.new(0,el.AbsoluteSize.X,0,0)})
                tw(arrow,0.15,{Rotation=0})
                task.wait(0.18); panel.Visible=false
            else
                opened=true
                local optH = positionPanel()
                panel.Visible=true
                tw(panel,0.2,{Size=UDim2.new(0,el.AbsoluteSize.X,0,optH)})
                tw(arrow,0.15,{Rotation=180})
            end
        end)

        if s.Flag then NoirX.Flags[s.Flag] = s end
        function s:Set(opt)
            if typeof(opt)=="string" then opt={opt} end
            s.CurrentOption=opt
            selLbl.Text=displayText()
            refreshPanel()
            task.spawn(function() pcall(s.Callback, s.CurrentOption) end)
        end
        return s
    end

    -- ---- KEYBIND ----
    function Tab:CreateKeybind(s)
        local el = mkElement(40)
        hoverEl(el)
        mkTitle(el, s.Name)

        local kbox = New("TextButton",{
            Size=UDim2.new(0,80,0,26),
            Position=UDim2.new(1,-90,0.5,-13),
            BackgroundColor3=T.BGDeep,BorderSizePixel=0,
            Text=s.CurrentKeybind or "None",
            TextColor3=T.Accent,TextSize=10,Font=Enum.Font.GothamBold,
            ZIndex=9,
        },el)
        Corner(7,kbox)
        Stroke(T.Border,0.6,kbox)

        local listening = false
        kbox.MouseButton1Click:Connect(function()
            listening=true
            kbox.Text="..."
            kbox.TextColor3=T.Warning
        end)

        UIS.InputBegan:Connect(function(input, processed)
            if listening then
                if input.KeyCode ~= Enum.KeyCode.Unknown then
                    local split = tostring(input.KeyCode):split(".")
                    local key   = split[3]
                    s.CurrentKeybind = key
                    kbox.Text = key
                    kbox.TextColor3 = T.Accent
                    listening = false
                    SaveConfig()
                end
            elseif not processed and s.CurrentKeybind then
                if UIS:GetFocusedTextBox() then return end
                pcall(function()
                    if input.KeyCode == Enum.KeyCode[s.CurrentKeybind] then
                        task.spawn(function() pcall(s.Callback) end)
                    end
                end)
            end
        end)

        if s.Flag then NoirX.Flags[s.Flag] = s end
        function s:Set(key)
            s.CurrentKeybind=tostring(key)
            kbox.Text=tostring(key)
        end
        return s
    end

    -- ---- COLOR PICKER (simplificado, funcional) ----
    function Tab:CreateColorPicker(s)
        s.Type = "ColorPicker"
        s.Color = s.Color or Color3.fromRGB(255,255,255)
        local h,sat,v = s.Color:ToHSV()

        local el = mkElement(40)
        hoverEl(el)
        mkTitle(el, s.Name)

        local preview = New("Frame",{
            Size=UDim2.new(0,28,0,20),
            Position=UDim2.new(1,-42,0.5,-10),
            BackgroundColor3=s.Color,BorderSizePixel=0,ZIndex=9,
        },el)
        Corner(6,preview)
        Stroke(T.Border,0.6,preview)

        -- expanded picker
        local picker = New("Frame",{
            Size=UDim2.new(1,0,0,0),
            BackgroundColor3=T.BGDeep,BorderSizePixel=0,
            ClipsDescendants=true,ZIndex=8,
        },Page)
        Corner(8,picker)
        Stroke(T.Border,0.5,picker)
        local pickerVisible = false

        -- hue slider
        local hueGrad = New("Frame",{
            Size=UDim2.new(1,-28,0,16),Position=UDim2.new(0,14,0,12),
            BorderSizePixel=0,ZIndex=9,
        },picker)
        Corner(4,hueGrad)
        local uiGrad = New("UIGradient",{},hueGrad)
        uiGrad.Color = ColorSequence.new({
            ColorSequenceKeypoint.new(0,   Color3.fromHSV(0,1,1)),
            ColorSequenceKeypoint.new(0.17, Color3.fromHSV(0.17,1,1)),
            ColorSequenceKeypoint.new(0.33, Color3.fromHSV(0.33,1,1)),
            ColorSequenceKeypoint.new(0.5,  Color3.fromHSV(0.5,1,1)),
            ColorSequenceKeypoint.new(0.67, Color3.fromHSV(0.67,1,1)),
            ColorSequenceKeypoint.new(0.83, Color3.fromHSV(0.83,1,1)),
            ColorSequenceKeypoint.new(1,    Color3.fromHSV(1,1,1)),
        })

        local hueHandle = New("Frame",{
            Size=UDim2.new(0,8,1,4),Position=UDim2.new(h,-4,-0.1,0),
            BackgroundColor3=T.White,BorderSizePixel=0,ZIndex=10,
        },hueGrad)
        Corner(3,hueHandle)

        local hexBox = New("TextBox",{
            Size=UDim2.new(1,-28,0,24),Position=UDim2.new(0,14,0,34),
            BackgroundColor3=T.Surface,BorderSizePixel=0,
            Text=string.format("#%02X%02X%02X",s.Color.R*255,s.Color.G*255,s.Color.B*255),
            TextColor3=T.Text,TextSize=10,Font=Enum.Font.GothamBold,
            ClearTextOnFocus=false,ZIndex=9,
        },picker)
        Corner(6,hexBox)
        Pad(8,8,0,0,hexBox)
        Stroke(T.Border,0.5,hexBox)

        local function applyColor()
            s.Color = Color3.fromHSV(h,sat,v)
            preview.BackgroundColor3 = s.Color
            hexBox.Text = string.format("#%02X%02X%02X",s.Color.R*255,s.Color.G*255,s.Color.B*255)
            task.spawn(function() pcall(s.Callback, s.Color) end)
            SaveConfig()
        end

        -- hue drag
        local hueDrag = false
        local hInt = New("TextButton",{
            Size=UDim2.new(1,0,1,0),BackgroundTransparency=1,Text="",ZIndex=11,
        },hueGrad)
        hInt.InputBegan:Connect(function(i)
            if i.UserInputType==Enum.UserInputType.MouseButton1 then hueDrag=true end
        end)
        UIS.InputEnded:Connect(function(i)
            if i.UserInputType==Enum.UserInputType.MouseButton1 then hueDrag=false end
        end)
        UIS.InputChanged:Connect(function(i)
            if hueDrag and i.UserInputType==Enum.UserInputType.MouseMovement then
                h = math.clamp((UIS:GetMouseLocation().X-hueGrad.AbsolutePosition.X)/hueGrad.AbsoluteSize.X,0,1)
                hueHandle.Position = UDim2.new(h,-4,-0.1,0)
                applyColor()
            end
        end)
        hInt.MouseButton1Down:Connect(function()
            h=math.clamp((UIS:GetMouseLocation().X-hueGrad.AbsolutePosition.X)/hueGrad.AbsoluteSize.X,0,1)
            hueHandle.Position=UDim2.new(h,-4,-0.1,0)
            applyColor()
        end)

        hexBox.FocusLost:Connect(function()
            pcall(function()
                local r,g,b=hexBox.Text:match("^#?(%x%x)(%x%x)(%x%x)$")
                s.Color=Color3.fromRGB(tonumber(r,16),tonumber(g,16),tonumber(b,16))
                h,sat,v=s.Color:ToHSV()
                preview.BackgroundColor3=s.Color
                task.spawn(function() pcall(s.Callback,s.Color) end)
                SaveConfig()
            end)
        end)

        -- toggle expand
        local interact = New("TextButton",{
            Size=UDim2.new(1,0,1,0),BackgroundTransparency=1,Text="",ZIndex=10,
        },el)
        interact.MouseButton1Click:Connect(function()
            pickerVisible = not pickerVisible
            if pickerVisible then
                picker.Visible=true
                tw(picker,0.2,{Size=UDim2.new(1,0,0,70)})
            else
                tw(picker,0.15,{Size=UDim2.new(1,0,0,0)})
                task.wait(0.18); picker.Visible=false
            end
        end)

        if s.Flag then NoirX.Flags[s.Flag] = s end
        function s:Set(color)
            s.Color=color; h,sat,v=color:ToHSV()
            preview.BackgroundColor3=color
            hexBox.Text=string.format("#%02X%02X%02X",color.R*255,color.G*255,color.B*255)
            task.spawn(function() pcall(s.Callback,color) end)
        end
        return s
    end

    return Tab
end -- CreateTab

-- ---- loading animation ----
task.spawn(function()
    -- simple fade in
    Main.BackgroundTransparency = 1
    ContentArea.Visible = false
    task.wait(0.05)
    tw(Main, 0.4, {BackgroundTransparency=0})
    task.wait(0.35)
    ContentArea.Visible = true
    -- load config after 3.5s like Rayfield
    task.wait(3.5)
    LoadConfig()
end)

return Window

end -- CreateWindow

-- ============================================================
-- DESTROY
-- ============================================================
function NoirX:Destroy()
Root:Destroy()
end

return NoirX

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions