1. --[[
  2. ECHELON UI LIBRARY v1.0
  3. Premium Dark / Cyber Glass UI Library for Roblox
  4. Usage: local EchelonUI = loadstring(game:HttpGet("URL"))()
  5. ]]
  6.  
  7. local EchelonUI = {}
  8. EchelonUI.__index = EchelonUI
  9. EchelonUI.Version = "1.0"
  10. EchelonUI.Name = "EchelonUI"
  11.  
  12. -- Services
  13. local Players = game:GetService("Players")
  14. local TweenService = game:GetService("TweenService")
  15. local UserInputService = game:GetService("UserInputService")
  16. local RunService = game:GetService("RunService")
  17. local HttpService = game:GetService("HttpService")
  18. local CoreGui = game:GetService("CoreGui")
  19. local GuiService = game:GetService("GuiService")
  20.  
  21. local LocalPlayer = Players.LocalPlayer
  22. local Mouse = LocalPlayer:GetMouse()
  23.  
  24. -- Utilities
  25. local function isMobile()
  26. return UserInputService.TouchEnabled and not UserInputService.KeyboardEnabled
  27. end
  28.  
  29. local function deepCopy(t)
  30. if type(t) ~= "table" then return t end
  31. local n = {}
  32. for k, v in pairs(t) do
  33. n[k] = deepCopy(v)
  34. end
  35. return n
  36. end
  37.  
  38. local function clamp(v, min, max)
  39. return math.max(min, math.min(max, v))
  40. end
  41.  
  42. local function round(n, step)
  43. if not step or step == 0 then return n end
  44. return math.floor(n / step + 0.5) * step
  45. end
  46.  
  47. local function create(class, props)
  48. local inst = Instance.new(class)
  49. for k, v in pairs(props or {}) do
  50. if k ~= "Parent" then
  51. inst[k] = v
  52. end
  53. end
  54. if props and props.Parent then
  55. inst.Parent = props.Parent
  56. end
  57. return inst
  58. end
  59.  
  60. local function tween(obj, props, duration, style, dir)
  61. local t = TweenService:Create(
  62. obj,
  63. TweenInfo.new(duration or 0.25, style or Enum.EasingStyle.Quint, dir or Enum.EasingDirection.Out),
  64. props
  65. )
  66. t:Play()
  67. return t
  68. end
  69.  
  70. local function makeCorner(parent, radius)
  71. return create("UICorner", { CornerRadius = UDim.new(0, radius or 8), Parent = parent })
  72. end
  73.  
  74. local function makeStroke(parent, color, thickness, transparency)
  75. return create("UIStroke", {
  76. Color = color or Color3.fromRGB(60, 60, 80),
  77. Thickness = thickness or 1,
  78. Transparency = transparency or 0.4,
  79. ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
  80. Parent = parent
  81. })
  82. end
  83.  
  84. local function makePadding(parent, t, b, l, r)
  85. return create("UIPadding", {
  86. PaddingTop = UDim.new(0, t or 0),
  87. PaddingBottom = UDim.new(0, b or 0),
  88. PaddingLeft = UDim.new(0, l or 0),
  89. PaddingRight = UDim.new(0, r or 0),
  90. Parent = parent
  91. })
  92. end
  93.  
  94. local function makeList(parent, pad, dir, hAlign, vAlign)
  95. return create("UIListLayout", {
  96. Padding = UDim.new(0, pad or 6),
  97. FillDirection = dir or Enum.FillDirection.Vertical,
  98. HorizontalAlignment = hAlign or Enum.HorizontalAlignment.Left,
  99. VerticalAlignment = vAlign or Enum.VerticalAlignment.Top,
  100. SortOrder = Enum.SortOrder.LayoutOrder,
  101. Parent = parent
  102. })
  103. end
  104.  
  105. -- ============================================================
  106. -- THEME SYSTEM
  107. -- ============================================================
  108. local ThemeRegistry = {} -- elements that react to theme changes
  109.  
  110. local DefaultThemes = {
  111. Aqua = {
  112. bg = Color3.fromRGB(12, 14, 22),
  113. bg2 = Color3.fromRGB(18, 22, 34),
  114. bg3 = Color3.fromRGB(24, 30, 46),
  115. bg4 = Color3.fromRGB(32, 40, 58),
  116. accent = Color3.fromRGB(0, 210, 200),
  117. accent2 = Color3.fromRGB(0, 160, 180),
  118. accent3 = Color3.fromRGB(40, 240, 220),
  119. accentGlow = Color3.fromRGB(0, 255, 240),
  120. text = Color3.fromRGB(235, 240, 250),
  121. text2 = Color3.fromRGB(160, 175, 200),
  122. text3 = Color3.fromRGB(100, 115, 140),
  123. border = Color3.fromRGB(45, 55, 80),
  124. borderSoft = Color3.fromRGB(30, 38, 55),
  125. red = Color3.fromRGB(255, 70, 90),
  126. green = Color3.fromRGB(60, 220, 140),
  127. gold = Color3.fromRGB(255, 200, 60),
  128. },
  129. Purple = {
  130. bg = Color3.fromRGB(14, 12, 22),
  131. bg2 = Color3.fromRGB(22, 18, 34),
  132. bg3 = Color3.fromRGB(30, 24, 46),
  133. bg4 = Color3.fromRGB(40, 32, 58),
  134. accent = Color3.fromRGB(170, 90, 255),
  135. accent2 = Color3.fromRGB(130, 60, 220),
  136. accent3 = Color3.fromRGB(200, 130, 255),
  137. accentGlow = Color3.fromRGB(190, 110, 255),
  138. text = Color3.fromRGB(235, 235, 250),
  139. text2 = Color3.fromRGB(170, 160, 200),
  140. text3 = Color3.fromRGB(110, 100, 140),
  141. border = Color3.fromRGB(55, 45, 80),
  142. borderSoft = Color3.fromRGB(38, 30, 55),
  143. red = Color3.fromRGB(255, 70, 90),
  144. green = Color3.fromRGB(60, 220, 140),
  145. gold = Color3.fromRGB(255, 200, 60),
  146. },
  147. Red = {
  148. bg = Color3.fromRGB(16, 12, 14),
  149. bg2 = Color3.fromRGB(26, 16, 20),
  150. bg3 = Color3.fromRGB(36, 22, 26),
  151. bg4 = Color3.fromRGB(48, 28, 34),
  152. accent = Color3.fromRGB(255, 70, 90),
  153. accent2 = Color3.fromRGB(200, 40, 60),
  154. accent3 = Color3.fromRGB(255, 120, 130),
  155. accentGlow = Color3.fromRGB(255, 90, 110),
  156. text = Color3.fromRGB(245, 235, 235),
  157. text2 = Color3.fromRGB(190, 160, 165),
  158. text3 = Color3.fromRGB(130, 100, 105),
  159. border = Color3.fromRGB(70, 40, 48),
  160. borderSoft = Color3.fromRGB(48, 28, 34),
  161. red = Color3.fromRGB(255, 70, 90),
  162. green = Color3.fromRGB(60, 220, 140),
  163. gold = Color3.fromRGB(255, 200, 60),
  164. },
  165. Blue = {
  166. bg = Color3.fromRGB(10, 14, 24),
  167. bg2 = Color3.fromRGB(14, 20, 36),
  168. bg3 = Color3.fromRGB(20, 28, 48),
  169. bg4 = Color3.fromRGB(28, 38, 62),
  170. accent = Color3.fromRGB(60, 140, 255),
  171. accent2 = Color3.fromRGB(40, 100, 220),
  172. accent3 = Color3.fromRGB(100, 180, 255),
  173. accentGlow = Color3.fromRGB(80, 160, 255),
  174. text = Color3.fromRGB(230, 240, 255),
  175. text2 = Color3.fromRGB(150, 175, 210),
  176. text3 = Color3.fromRGB(90, 115, 150),
  177. border = Color3.fromRGB(40, 55, 90),
  178. borderSoft = Color3.fromRGB(28, 38, 60),
  179. red = Color3.fromRGB(255, 70, 90),
  180. green = Color3.fromRGB(60, 220, 140),
  181. gold = Color3.fromRGB(255, 200, 60),
  182. },
  183. }
  184.  
  185. local CurrentTheme = deepCopy(DefaultThemes.Aqua)
  186. local CustomThemes = {}
  187.  
  188. function EchelonUI:AddTheme(name, data)
  189. CustomThemes[name] = data
  190. end
  191.  
  192. function EchelonUI:GetTheme(name)
  193. return CustomThemes[name] or DefaultThemes[name] or CurrentTheme
  194. end
  195.  
  196. local function applyThemeToRegistry()
  197. for _, entry in ipairs(ThemeRegistry) do
  198. if entry and entry.Update then
  199. pcall(entry.Update, CurrentTheme)
  200. end
  201. end
  202. end
  203.  
  204. local function registerTheme(updateFn)
  205. local entry = { Update = updateFn }
  206. table.insert(ThemeRegistry, entry)
  207. return entry
  208. end
  209.  
  210. -- ============================================================
  211. -- ICON SYSTEM
  212. -- ============================================================
  213. local IconPack = "lucide"
  214. local IconCache = {}
  215. local IconsModule = nil
  216.  
  217. local function loadIcons()
  218. if IconsModule then return IconsModule end
  219. local sources = {
  220. }
  221. for _, url in ipairs(sources) do
  222. local ok, result = pcall(function()
  223. return loadstring(game:HttpGet(url))()
  224. end)
  225. if ok and result then
  226. IconsModule = result
  227. return IconsModule
  228. end
  229. end
  230. return nil
  231. end
  232.  
  233. function EchelonUI:SetIconPack(pack)
  234. IconPack = pack or "lucide"
  235. IconCache = {}
  236. end
  237.  
  238. function EchelonUI:GetIcon(name)
  239. if not name or name == "" then return nil end
  240. if typeof(name) == "string" and name:find("rbxassetid://") then
  241. return { Image = name, ImageRectSize = Vector2.new(0, 0), ImageRectOffset = Vector2.new(0, 0) }
  242. end
  243. if IconCache[name] then return IconCache[name] end
  244. local mod = loadIcons()
  245. if mod and mod.GetIcon then
  246. local ok, data = pcall(mod.GetIcon, name, IconPack)
  247. if ok and data then
  248. IconCache[name] = data
  249. return data
  250. end
  251. end
  252. -- fallback empty
  253. return { Image = "rbxassetid://0", ImageRectSize = Vector2.new(0, 0), ImageRectOffset = Vector2.new(0, 0) }
  254. end
  255.  
  256. local function applyIcon(imageLabel, iconName, color)
  257. local data = EchelonUI:GetIcon(iconName)
  258. if not data then return end
  259. imageLabel.Image = data.Image or data
  260. if data.ImageRectSize and data.ImageRectSize.X > 0 then
  261. imageLabel.ImageRectSize = data.ImageRectSize
  262. imageLabel.ImageRectOffset = data.ImageRectOffset or Vector2.new(0, 0)
  263. end
  264. if color then
  265. imageLabel.ImageColor3 = color
  266. end
  267. end
  268.  
  269. -- ============================================================
  270. -- CONFIG SYSTEM
  271. -- ============================================================
  272. local ConfigFolder = "EchelonUI_Configs"
  273. local ConfigData = {} -- in-memory + file if possible
  274. local FlagMap = {} -- Flag -> {Set, Get}
  275.  
  276. local function ensureFolder()
  277. if not isfolder then return false end
  278. if not isfolder(ConfigFolder) then
  279. pcall(makefolder, ConfigFolder)
  280. end
  281. return true
  282. end
  283.  
  284. function EchelonUI:SaveConfig(name)
  285. name = name or "default"
  286. local data = {}
  287. for flag, handlers in pairs(FlagMap) do
  288. if handlers.Get then
  289. data[flag] = handlers.Get()
  290. end
  291. end
  292. ConfigData[name] = data
  293. if ensureFolder() and writefile then
  294. pcall(writefile, ConfigFolder .. "/" .. name .. ".json", HttpService:JSONEncode(data))
  295. end
  296. return true
  297. end
  298.  
  299. function EchelonUI:LoadConfig(name)
  300. name = name or "default"
  301. local data = ConfigData[name]
  302. if not data and ensureFolder() and readfile and isfile then
  303. local path = ConfigFolder .. "/" .. name .. ".json"
  304. if isfile(path) then
  305. local ok, decoded = pcall(function()
  306. return HttpService:JSONDecode(readfile(path))
  307. end)
  308. if ok and decoded then
  309. data = decoded
  310. ConfigData[name] = data
  311. end
  312. end
  313. end
  314. if not data then return false end
  315. for flag, value in pairs(data) do
  316. local handlers = FlagMap[flag]
  317. if handlers and handlers.Set then
  318. pcall(handlers.Set, value)
  319. end
  320. end
  321. return true
  322. end
  323.  
  324. function EchelonUI:DeleteConfig(name)
  325. name = name or "default"
  326. ConfigData[name] = nil
  327. if ensureFolder() and isfile and delfile then
  328. local path = ConfigFolder .. "/" .. name .. ".json"
  329. if isfile(path) then pcall(delfile, path) end
  330. end
  331. end
  332.  
  333. function EchelonUI:GetConfigs()
  334. local list = {}
  335. for k in pairs(ConfigData) do
  336. table.insert(list, k)
  337. end
  338. if ensureFolder() and listfiles then
  339. local ok, files = pcall(listfiles, ConfigFolder)
  340. if ok and files then
  341. for _, f in ipairs(files) do
  342. local n = f:match("([^/\\]+)%.json$")
  343. if n and not table.find(list, n) then
  344. table.insert(list, n)
  345. end
  346. end
  347. end
  348. end
  349. return list
  350. end
  351.  
  352. local function registerFlag(flag, getFn, setFn)
  353. if not flag or flag == "" then return end
  354. FlagMap[flag] = { Get = getFn, Set = setFn }
  355. end
  356.  
  357. -- ============================================================
  358. -- PLATFORM HELPERS
  359. -- ============================================================
  360. function EchelonUI:GetPlatform()
  361. if isMobile() then return "Mobile" end
  362. return "PC"
  363. end
  364.  
  365. function EchelonUI:GetExecutor()
  366. local names = { "Synapse", "Script-Ware", "Krnl", "Fluxus", "Oxygen", "Electron", "Delta", "Codex", "Solara", "Wave" }
  367. for _, n in ipairs(names) do
  368. if identifyexecutor and identifyexecutor():lower():find(n:lower()) then
  369. return n
  370. end
  371. end
  372. if identifyexecutor then return identifyexecutor() end
  373. return "Unknown"
  374. end
  375.  
  376. -- ============================================================
  377. -- NOTIFICATION SYSTEM
  378. -- ============================================================
  379. local NotifyContainer = nil
  380. local ActiveNotifies = {}
  381.  
  382. local function ensureNotifyContainer()
  383. if NotifyContainer and NotifyContainer.Parent then return NotifyContainer end
  384. local gui = create("ScreenGui", {
  385. Name = "EchelonUI_Notifications",
  386. ResetOnSpawn = false,
  387. ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
  388. DisplayOrder = 9999,
  389. Parent = (gethui and gethui()) or CoreGui
  390. })
  391. NotifyContainer = create("Frame", {
  392. Name = "Container",
  393. BackgroundTransparency = 1,
  394. Size = UDim2.new(0, 320, 1, -40),
  395. Position = UDim2.new(1, -340, 0, 20),
  396. Parent = gui
  397. })
  398. makeList(NotifyContainer, 8, Enum.FillDirection.Vertical, Enum.HorizontalAlignment.Right, Enum.VerticalAlignment.Top)
  399. return NotifyContainer
  400. end
  401.  
  402. local TypeColors = {
  403. Success = function(t) return t.green end,
  404. Error = function(t) return t.red end,
  405. Warning = function(t) return t.gold end,
  406. Info = function(t) return t.accent end,
  407. }
  408.  
  409. function EchelonUI:Notify(opts)
  410. opts = opts or {}
  411. local title = opts.Title or "Notification"
  412. local content = opts.Content or ""
  413. local nType = opts.Type or "Info"
  414. local duration = opts.Duration or 4
  415. local theme = CurrentTheme
  416.  
  417. local container = ensureNotifyContainer()
  418. local accent = (TypeColors[nType] or TypeColors.Info)(theme)
  419.  
  420. local card = create("Frame", {
  421. Name = "Notify",
  422. BackgroundColor3 = theme.bg2,
  423. BackgroundTransparency = 0.1,
  424. Size = UDim2.new(1, 0, 0, 0),
  425. ClipsDescendants = true,
  426. Parent = container
  427. })
  428. makeCorner(card, 10)
  429. local stroke = makeStroke(card, accent, 1.2, 0.3)
  430.  
  431. local accentBar = create("Frame", {
  432. BackgroundColor3 = accent,
  433. BorderSizePixel = 0,
  434. Size = UDim2.new(0, 3, 1, 0),
  435. Parent = card
  436. })
  437. makeCorner(accentBar, 2)
  438.  
  439. local titleL = create("TextLabel", {
  440. BackgroundTransparency = 1,
  441. Position = UDim2.new(0, 14, 0, 8),
  442. Size = UDim2.new(1, -40, 0, 18),
  443. Font = Enum.Font.GothamBold,
  444. Text = title,
  445. TextColor3 = theme.text,
  446. TextSize = 14,
  447. TextXAlignment = Enum.TextXAlignment.Left,
  448. Parent = card
  449. })
  450.  
  451. local contentL = create("TextLabel", {
  452. BackgroundTransparency = 1,
  453. Position = UDim2.new(0, 14, 0, 28),
  454. Size = UDim2.new(1, -24, 0, 0),
  455. Font = Enum.Font.Gotham,
  456. Text = content,
  457. TextColor3 = theme.text2,
  458. TextSize = 12,
  459. TextXAlignment = Enum.TextXAlignment.Left,
  460. TextWrapped = true,
  461. Parent = card
  462. })
  463. contentL.Size = UDim2.new(1, -24, 0, contentL.TextBounds.Y + 4)
  464. card.Size = UDim2.new(1, 0, 0, 40 + contentL.TextBounds.Y)
  465.  
  466. local closeBtn = create("TextButton", {
  467. BackgroundTransparency = 1,
  468. Position = UDim2.new(1, -28, 0, 6),
  469. Size = UDim2.new(0, 22, 0, 22),
  470. Text = "×",
  471. Font = Enum.Font.GothamBold,
  472. TextSize = 16,
  473. TextColor3 = theme.text3,
  474. Parent = card
  475. })
  476.  
  477. local progress = create("Frame", {
  478. BackgroundColor3 = accent,
  479. BorderSizePixel = 0,
  480. Position = UDim2.new(0, 0, 1, -2),
  481. Size = UDim2.new(1, 0, 0, 2),
  482. Parent = card
  483. })
  484.  
  485. card.Position = UDim2.new(1, 40, 0, 0)
  486. tween(card, { Position = UDim2.new(0, 0, 0, 0) }, 0.35)
  487.  
  488. local closed = false
  489. local function close()
  490. if closed then return end
  491. closed = true
  492. tween(card, { Position = UDim2.new(1, 40, 0, 0), BackgroundTransparency = 1 }, 0.3)
  493. task.delay(0.35, function()
  494. if card then card:Destroy() end
  495. end)
  496. end
  497.  
  498. closeBtn.MouseButton1Click:Connect(close)
  499. tween(progress, { Size = UDim2.new(0, 0, 0, 2) }, duration, Enum.EasingStyle.Linear)
  500. task.delay(duration, close)
  501.  
  502. registerTheme(function(t)
  503. if not card or not card.Parent then return end
  504. card.BackgroundColor3 = t.bg2
  505. titleL.TextColor3 = t.text
  506. contentL.TextColor3 = t.text2
  507. local a = (TypeColors[nType] or TypeColors.Info)(t)
  508. accentBar.BackgroundColor3 = a
  509. progress.BackgroundColor3 = a
  510. stroke.Color = a
  511. end)
  512. end
  513.  
  514. -- ============================================================
  515. -- WINDOW
  516. -- ============================================================
  517. local Windows = {}
  518.  
  519. function EchelonUI:CreateWindow(opts)
  520. opts = opts or {}
  521. local title = opts.Title or "ECHELON UI"
  522. local subTitle = opts.SubTitle or opts.Version or "1.0"
  523. local logoId = opts.Logo
  524. local size = opts.Size or UDim2.fromOffset(500, 580)
  525. local mobileSize = opts.MobileSize or UDim2.fromOffset(340, 420)
  526. local themeName = opts.Theme or "Aqua"
  527. local bgTrans = opts.BackgroundTransparency or 0.05
  528. local titleAnim = opts.TitleAnimation ~= false
  529. local draggable = opts.Draggable ~= false
  530. local minimizable = opts.Minimizable ~= false
  531. local closable = opts.Closable ~= false
  532. local keybind = opts.Keybind or Enum.KeyCode.RightShift
  533. local cornerR = opts.CornerRadius or 12
  534. local strokeT = opts.StrokeThickness or 1.2
  535. local showStatus = opts.ShowStatusBar ~= false
  536. local loadingScreen = opts.LoadingScreen ~= false
  537. local accentOverride = opts.AccentColor
  538. local fontTitle = opts.FontTitle or Enum.Font.GothamBold
  539. local fontBody = opts.FontBody or Enum.Font.Gotham
  540.  
  541. -- Apply theme
  542. local themeData = EchelonUI:GetTheme(themeName)
  543. CurrentTheme = deepCopy(themeData)
  544. if accentOverride then
  545. CurrentTheme.accent = accentOverride
  546. CurrentTheme.accent2 = accentOverride
  547. CurrentTheme.accent3 = accentOverride
  548. CurrentTheme.accentGlow = accentOverride
  549. end
  550.  
  551. local finalSize = isMobile() and mobileSize or size
  552. local guiParent = (gethui and gethui()) or CoreGui
  553.  
  554. local screenGui = create("ScreenGui", {
  555. Name = "EchelonUI_" .. HttpService:GenerateGUID(false):sub(1, 8),
  556. ResetOnSpawn = false,
  557. ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
  558. DisplayOrder = 100,
  559. Parent = guiParent
  560. })
  561.  
  562. -- Loading Screen
  563. local loadingFrame = nil
  564. if loadingScreen then
  565. loadingFrame = create("Frame", {
  566. Name = "Loading",
  567. BackgroundColor3 = CurrentTheme.bg,
  568. Size = UDim2.fromScale(1, 1),
  569. ZIndex = 50,
  570. Parent = screenGui
  571. })
  572. local loadLogo = create("ImageLabel", {
  573. BackgroundTransparency = 1,
  574. AnchorPoint = Vector2.new(0.5, 0.5),
  575. Position = UDim2.fromScale(0.5, 0.38),
  576. Size = UDim2.fromOffset(64, 64),
  577. Image = logoId or "rbxassetid://0",
  578. ImageColor3 = CurrentTheme.accent,
  579. Parent = loadingFrame
  580. })
  581. makeCorner(loadLogo, 12)
  582. local loadTitle = create("TextLabel", {
  583. BackgroundTransparency = 1,
  584. AnchorPoint = Vector2.new(0.5, 0),
  585. Position = UDim2.new(0.5, 0, 0.38, 80),
  586. Size = UDim2.new(0, 300, 0, 28),
  587. Font = fontTitle,
  588. Text = title,
  589. TextColor3 = CurrentTheme.text,
  590. TextSize = 22,
  591. Parent = loadingFrame
  592. })
  593. local loadVer = create("TextLabel", {
  594. BackgroundTransparency = 1,
  595. AnchorPoint = Vector2.new(0.5, 0),
  596. Position = UDim2.new(0.5, 0, 0.38, 110),
  597. Size = UDim2.new(0, 200, 0, 18),
  598. Font = fontBody,
  599. Text = "v" .. subTitle,
  600. TextColor3 = CurrentTheme.text2,
  601. TextSize = 13,
  602. Parent = loadingFrame
  603. })
  604. local progressBg = create("Frame", {
  605. BackgroundColor3 = CurrentTheme.bg3,
  606. AnchorPoint = Vector2.new(0.5, 0),
  607. Position = UDim2.new(0.5, 0, 0.38, 150),
  608. Size = UDim2.new(0, 200, 0, 4),
  609. Parent = loadingFrame
  610. })
  611. makeCorner(progressBg, 2)
  612. local progressFill = create("Frame", {
  613. BackgroundColor3 = CurrentTheme.accent,
  614. Size = UDim2.new(0, 0, 1, 0),
  615. Parent = progressBg
  616. })
  617. makeCorner(progressFill, 2)
  618. local statusText = create("TextLabel", {
  619. BackgroundTransparency = 1,
  620. AnchorPoint = Vector2.new(0.5, 0),
  621. Position = UDim2.new(0.5, 0, 0.38, 165),
  622. Size = UDim2.new(0, 250, 0, 16),
  623. Font = fontBody,
  624. Text = "Initializing...",
  625. TextColor3 = CurrentTheme.text3,
  626. TextSize = 11,
  627. Parent = loadingFrame
  628. })
  629.  
  630. task.spawn(function()
  631. local steps = { "Loading assets", "Building interface", "Applying theme", "Ready" }
  632. for i, s in ipairs(steps) do
  633. statusText.Text = s
  634. tween(progressFill, { Size = UDim2.new(i / #steps, 0, 1, 0) }, 0.25)
  635. task.wait(0.22)
  636. end
  637. tween(loadingFrame, { BackgroundTransparency = 1 }, 0.4)
  638. for _, c in ipairs(loadingFrame:GetDescendants()) do
  639. if c:IsA("TextLabel") or c:IsA("ImageLabel") then
  640. tween(c, { TextTransparency = 1, ImageTransparency = 1 }, 0.35)
  641. elseif c:IsA("Frame") then
  642. tween(c, { BackgroundTransparency = 1 }, 0.35)
  643. end
  644. end
  645. task.wait(0.45)
  646. if loadingFrame then loadingFrame:Destroy() end
  647. end)
  648. end
  649.  
  650. -- Main Window
  651. local main = create("Frame", {
  652. Name = "Main",
  653. BackgroundColor3 = CurrentTheme.bg,
  654. BackgroundTransparency = bgTrans,
  655. Size = finalSize,
  656. Position = UDim2.fromScale(0.5, 0.5),
  657. AnchorPoint = Vector2.new(0.5, 0.5),
  658. ClipsDescendants = true,
  659. Visible = not loadingScreen,
  660. Parent = screenGui
  661. })
  662. makeCorner(main, cornerR)
  663. local mainStroke = makeStroke(main, CurrentTheme.border, strokeT, 0.35)
  664.  
  665. -- Top gradient line
  666. local topLine = create("Frame", {
  667. Name = "TopLine",
  668. BackgroundColor3 = CurrentTheme.accent,
  669. BorderSizePixel = 0,
  670. Size = UDim2.new(1, 0, 0, 2),
  671. Position = UDim2.new(0, 0, 0, 0),
  672. ZIndex = 5,
  673. Parent = main
  674. })
  675. local topGrad = create("UIGradient", {
  676. Color = ColorSequence.new({
  677. ColorSequenceKeypoint.new(0, CurrentTheme.accent),
  678. ColorSequenceKeypoint.new(0.5, CurrentTheme.accent3),
  679. ColorSequenceKeypoint.new(1, CurrentTheme.accent2),
  680. }),
  681. Parent = topLine
  682. })
  683.  
  684. if titleAnim then
  685. task.spawn(function()
  686. while topLine and topLine.Parent do
  687. tween(topGrad, { Offset = Vector2.new(1, 0) }, 2.5, Enum.EasingStyle.Linear)
  688. task.wait(2.5)
  689. topGrad.Offset = Vector2.new(-1, 0)
  690. end
  691. end)
  692. end
  693.  
  694. -- Title Bar
  695. local titleBar = create("Frame", {
  696. Name = "TitleBar",
  697. BackgroundColor3 = CurrentTheme.bg2,
  698. BackgroundTransparency = 0.3,
  699. Size = UDim2.new(1, 0, 0, 48),
  700. Parent = main
  701. })
  702. -- only bottom corners avoided by clipping
  703.  
  704. local logoImg = nil
  705. if logoId then
  706. logoImg = create("ImageLabel", {
  707. BackgroundTransparency = 1,
  708. Position = UDim2.new(0, 12, 0.5, 0),
  709. AnchorPoint = Vector2.new(0, 0.5),
  710. Size = UDim2.fromOffset(28, 28),
  711. Image = logoId,
  712. Parent = titleBar
  713. })
  714. makeCorner(logoImg, 6)
  715. end
  716.  
  717. local titleLabel = create("TextLabel", {
  718. BackgroundTransparency = 1,
  719. Position = UDim2.new(0, logoId and 48 or 14, 0, 6),
  720. Size = UDim2.new(1, -140, 0, 20),
  721. Font = fontTitle,
  722. Text = title,
  723. TextColor3 = CurrentTheme.text,
  724. TextSize = 15,
  725. TextXAlignment = Enum.TextXAlignment.Left,
  726. Parent = titleBar
  727. })
  728.  
  729. local subLabel = create("TextLabel", {
  730. BackgroundTransparency = 1,
  731. Position = UDim2.new(0, logoId and 48 or 14, 0, 26),
  732. Size = UDim2.new(1, -140, 0, 14),
  733. Font = fontBody,
  734. Text = subTitle,
  735. TextColor3 = CurrentTheme.text3,
  736. TextSize = 11,
  737. TextXAlignment = Enum.TextXAlignment.Left,
  738. Parent = titleBar
  739. })
  740.  
  741. -- Window controls
  742. local controls = create("Frame", {
  743. BackgroundTransparency = 1,
  744. Position = UDim2.new(1, -90, 0.5, 0),
  745. AnchorPoint = Vector2.new(0, 0.5),
  746. Size = UDim2.fromOffset(80, 28),
  747. Parent = titleBar
  748. })
  749. makeList(controls, 4, Enum.FillDirection.Horizontal, Enum.HorizontalAlignment.Right)
  750.  
  751. local function makeControlBtn(txt, color)
  752. local b = create("TextButton", {
  753. BackgroundColor3 = CurrentTheme.bg3,
  754. Size = UDim2.fromOffset(24, 24),
  755. Text = txt,
  756. Font = Enum.Font.GothamBold,
  757. TextSize = 12,
  758. TextColor3 = color or CurrentTheme.text2,
  759. AutoButtonColor = false,
  760. Parent = controls
  761. })
  762. makeCorner(b, 6)
  763. b.MouseEnter:Connect(function()
  764. tween(b, { BackgroundColor3 = CurrentTheme.bg4 }, 0.15)
  765. end)
  766. b.MouseLeave:Connect(function()
  767. tween(b, { BackgroundColor3 = CurrentTheme.bg3 }, 0.15)
  768. end)
  769. return b
  770. end
  771.  
  772. local minimized = false
  773. local minBtn, closeBtn
  774. if minimizable then
  775. minBtn = makeControlBtn("–")
  776. end
  777. if closable then
  778. closeBtn = makeControlBtn("×", CurrentTheme.red)
  779. end
  780.  
  781. -- Tab bar (left)
  782. local tabBarWidth = 58
  783. local tabBar = create("Frame", {
  784. Name = "TabBar",
  785. BackgroundColor3 = CurrentTheme.bg2,
  786. BackgroundTransparency = 0.25,
  787. Position = UDim2.new(0, 0, 0, 48),
  788. Size = UDim2.new(0, tabBarWidth, 1, showStatus and -70 or -48),
  789. Parent = main
  790. })
  791.  
  792. local tabList = create("ScrollingFrame", {
  793. BackgroundTransparency = 1,
  794. Size = UDim2.fromScale(1, 1),
  795. CanvasSize = UDim2.new(0, 0, 0, 0),
  796. ScrollBarThickness = 0,
  797. BorderSizePixel = 0,
  798. Parent = tabBar
  799. })
  800. makeList(tabList, 4, Enum.FillDirection.Vertical, Enum.HorizontalAlignment.Center)
  801. makePadding(tabList, 8, 8, 6, 6)
  802.  
  803. -- Content area
  804. local contentArea = create("Frame", {
  805. Name = "Content",
  806. BackgroundTransparency = 1,
  807. Position = UDim2.new(0, tabBarWidth, 0, 48),
  808. Size = UDim2.new(1, -tabBarWidth, 1, showStatus and -70 or -48),
  809. ClipsDescendants = true,
  810. Parent = main
  811. })
  812.  
  813. -- Status bar
  814. local statusBar = nil
  815. if showStatus then
  816. statusBar = create("Frame", {
  817. Name = "StatusBar",
  818. BackgroundColor3 = CurrentTheme.bg2,
  819. BackgroundTransparency = 0.3,
  820. Position = UDim2.new(0, 0, 1, -22),
  821. Size = UDim2.new(1, 0, 0, 22),
  822. Parent = main
  823. })
  824. local statusL = create("TextLabel", {
  825. BackgroundTransparency = 1,
  826. Size = UDim2.fromScale(1, 1),
  827. Font = fontBody,
  828. Text = " " .. EchelonUI:GetPlatform() .. " | " .. EchelonUI:GetExecutor() .. " | EchelonUI " .. EchelonUI.Version,
  829. TextColor3 = CurrentTheme.text3,
  830. TextSize = 10,
  831. TextXAlignment = Enum.TextXAlignment.Left,
  832. Parent = statusBar
  833. })
  834. end
  835.  
  836. -- Dragging
  837. if draggable then
  838. local dragging, dragStart, startPos
  839. titleBar.InputBegan:Connect(function(input)
  840. if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
  841. dragging = true
  842. dragStart = input.Position
  843. startPos = main.Position
  844. end
  845. end)
  846. titleBar.InputEnded:Connect(function(input)
  847. if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
  848. dragging = false
  849. end
  850. end)
  851. UserInputService.InputChanged:Connect(function(input)
  852. if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then
  853. local delta = input.Position - dragStart
  854. main.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + delta.X, startPos.Y.Scale, startPos.Y.Offset + delta.Y)
  855. end
  856. end)
  857. end
  858.  
  859. -- Minimize
  860. local originalSize = finalSize
  861. if minBtn then
  862. minBtn.MouseButton1Click:Connect(function()
  863. minimized = not minimized
  864. if minimized then
  865. tween(main, { Size = UDim2.fromOffset(finalSize.X.Offset, 48) }, 0.3)
  866. contentArea.Visible = false
  867. tabBar.Visible = false
  868. if statusBar then statusBar.Visible = false end
  869. else
  870. tween(main, { Size = originalSize }, 0.3)
  871. contentArea.Visible = true
  872. tabBar.Visible = true
  873. if statusBar then statusBar.Visible = true end
  874. end
  875. end)
  876. end
  877.  
  878. -- Close
  879. if closeBtn then
  880. closeBtn.MouseButton1Click:Connect(function()
  881. tween(main, { Size = UDim2.fromOffset(0, 0), BackgroundTransparency = 1 }, 0.25)
  882. task.delay(0.3, function()
  883. screenGui:Destroy()
  884. end)
  885. end)
  886. end
  887.  
  888. -- Keybind toggle
  889. local visible = true
  890. UserInputService.InputBegan:Connect(function(input, gpe)
  891. if gpe then return end
  892. if input.KeyCode == keybind then
  893. visible = not visible
  894. main.Visible = visible
  895. end
  896. end)
  897.  
  898. -- Theme live update registration
  899. registerTheme(function(t)
  900. main.BackgroundColor3 = t.bg
  901. mainStroke.Color = t.border
  902. titleBar.BackgroundColor3 = t.bg2
  903. titleLabel.TextColor3 = t.text
  904. subLabel.TextColor3 = t.text3
  905. tabBar.BackgroundColor3 = t.bg2
  906. topLine.BackgroundColor3 = t.accent
  907. topGrad.Color = ColorSequence.new({
  908. ColorSequenceKeypoint.new(0, t.accent),
  909. ColorSequenceKeypoint.new(0.5, t.accent3),
  910. ColorSequenceKeypoint.new(1, t.accent2),
  911. })
  912. if statusBar then
  913. statusBar.BackgroundColor3 = t.bg2
  914. end
  915. end)
  916.  
  917. -- Window object
  918. local Window = {}
  919. Window._gui = screenGui
  920. Window._main = main
  921. Window._tabs = {}
  922. Window._currentTab = nil
  923. Window._theme = CurrentTheme
  924.  
  925. function Window:SetTheme(name)
  926. local t = EchelonUI:GetTheme(name)
  927. if not t then return end
  928. CurrentTheme = deepCopy(t)
  929. applyThemeToRegistry()
  930. end
  931.  
  932. function Window:SetBackgroundTransparency(v)
  933. bgTrans = clamp(v, 0, 0.6)
  934. main.BackgroundTransparency = bgTrans
  935. end
  936.  
  937. function Window:SetTitleAnimation(enabled)
  938. titleAnim = enabled
  939. end
  940.  
  941. function Window:Notify(opts)
  942. EchelonUI:Notify(opts)
  943. end
  944.  
  945. function Window:Destroy()
  946. screenGui:Destroy()
  947. end
  948.  
  949. -- ========================================================
  950. -- TAB
  951. -- ========================================================
  952. function Window:CreateTab(tabOpts)
  953. tabOpts = tabOpts or {}
  954. local tabName = tabOpts.Name or "Tab"
  955. local tabIcon = tabOpts.Icon or "circle"
  956. local order = tabOpts.Order or (#Window._tabs + 1)
  957.  
  958. local tabBtn = create("TextButton", {
  959. BackgroundColor3 = CurrentTheme.bg3,
  960. BackgroundTransparency = 0.4,
  961. Size = UDim2.fromOffset(44, 44),
  962. Text = "",
  963. AutoButtonColor = false,
  964. LayoutOrder = order,
  965. Parent = tabList
  966. })
  967. makeCorner(tabBtn, 10)
  968.  
  969. local iconImg = create("ImageLabel", {
  970. BackgroundTransparency = 1,
  971. AnchorPoint = Vector2.new(0.5, 0.5),
  972. Position = UDim2.fromScale(0.5, 0.5),
  973. Size = UDim2.fromOffset(20, 20),
  974. Parent = tabBtn
  975. })
  976. applyIcon(iconImg, tabIcon, CurrentTheme.text2)
  977.  
  978. local indicator = create("Frame", {
  979. BackgroundColor3 = CurrentTheme.accent,
  980. Size = UDim2.new(0, 3, 0, 0),
  981. Position = UDim2.new(0, 0, 0.5, 0),
  982. AnchorPoint = Vector2.new(0, 0.5),
  983. Visible = false,
  984. Parent = tabBtn
  985. })
  986. makeCorner(indicator, 2)
  987.  
  988. local page = create("ScrollingFrame", {
  989. Name = tabName,
  990. BackgroundTransparency = 1,
  991. Size = UDim2.fromScale(1, 1),
  992. CanvasSize = UDim2.new(0, 0, 0, 0),
  993. ScrollBarThickness = 3,
  994. ScrollBarImageColor3 = CurrentTheme.accent,
  995. BorderSizePixel = 0,
  996. Visible = false,
  997. Parent = contentArea
  998. })
  999. makePadding(page, 10, 10, 12, 12)
  1000. local pageLayout = makeList(page, 8)
  1001. pageLayout:GetPropertyChangedSignal("AbsoluteContentSize"):Connect(function()
  1002. page.CanvasSize = UDim2.new(0, 0, 0, pageLayout.AbsoluteContentSize.Y + 20)
  1003. end)
  1004.  
  1005. local Tab = {
  1006. _btn = tabBtn,
  1007. _page = page,
  1008. _name = tabName,
  1009. }
  1010.  
  1011. local function selectTab()
  1012. for _, t in ipairs(Window._tabs) do
  1013. t._page.Visible = false
  1014. t._btn.BackgroundTransparency = 0.4
  1015. t._btn.BackgroundColor3 = CurrentTheme.bg3
  1016. local ind = t._btn:FindFirstChild("Frame")
  1017. if ind then ind.Visible = false; ind.Size = UDim2.new(0, 3, 0, 0) end
  1018. local ic = t._btn:FindFirstChildOfClass("ImageLabel")
  1019. if ic then ic.ImageColor3 = CurrentTheme.text2 end
  1020. end
  1021. page.Visible = true
  1022. tabBtn.BackgroundTransparency = 0.1
  1023. tabBtn.BackgroundColor3 = CurrentTheme.bg4
  1024. indicator.Visible = true
  1025. tween(indicator, { Size = UDim2.new(0, 3, 0.6, 0) }, 0.2)
  1026. iconImg.ImageColor3 = CurrentTheme.accent
  1027. Window._currentTab = Tab
  1028. end
  1029.  
  1030. tabBtn.MouseButton1Click:Connect(selectTab)
  1031. tabBtn.MouseEnter:Connect(function()
  1032. if Window._currentTab ~= Tab then
  1033. tween(tabBtn, { BackgroundTransparency = 0.2 }, 0.15)
  1034. end
  1035. end)
  1036. tabBtn.MouseLeave:Connect(function()
  1037. if Window._currentTab ~= Tab then
  1038. tween(tabBtn, { BackgroundTransparency = 0.4 }, 0.15)
  1039. end
  1040. end)
  1041.  
  1042. registerTheme(function(t)
  1043. tabBtn.BackgroundColor3 = (Window._currentTab == Tab) and t.bg4 or t.bg3
  1044. iconImg.ImageColor3 = (Window._currentTab == Tab) and t.accent or t.text2
  1045. indicator.BackgroundColor3 = t.accent
  1046. page.ScrollBarImageColor3 = t.accent
  1047. end)
  1048.  
  1049. table.insert(Window._tabs, Tab)
  1050. if #Window._tabs == 1 then
  1051. selectTab()
  1052. end
  1053.  
  1054. -- Auto canvas
  1055. tabList.CanvasSize = UDim2.new(0, 0, 0, (#Window._tabs) * 48 + 16)
  1056.  
  1057. -- ====================================================
  1058. -- SECTION
  1059. -- ====================================================
  1060. function Tab:CreateSection(secOpts)
  1061. secOpts = secOpts or {}
  1062. local secTitle = secOpts.Title or "Section"
  1063. local secIcon = secOpts.Icon
  1064.  
  1065. local sec = create("Frame", {
  1066. BackgroundTransparency = 1,
  1067. Size = UDim2.new(1, 0, 0, 28),
  1068. Parent = page
  1069. })
  1070. local bar = create("Frame", {
  1071. BackgroundColor3 = CurrentTheme.accent,
  1072. Size = UDim2.new(0, 3, 0, 14),
  1073. Position = UDim2.new(0, 0, 0.5, 0),
  1074. AnchorPoint = Vector2.new(0, 0.5),
  1075. Parent = sec
  1076. })
  1077. makeCorner(bar, 2)
  1078.  
  1079. local iconS = nil
  1080. if secIcon then
  1081. iconS = create("ImageLabel", {
  1082. BackgroundTransparency = 1,
  1083. Position = UDim2.new(0, 10, 0.5, 0),
  1084. AnchorPoint = Vector2.new(0, 0.5),
  1085. Size = UDim2.fromOffset(14, 14),
  1086. Parent = sec
  1087. })
  1088. applyIcon(iconS, secIcon, CurrentTheme.accent)
  1089. end
  1090.  
  1091. local titleS = create("TextLabel", {
  1092. BackgroundTransparency = 1,
  1093. Position = UDim2.new(0, secIcon and 28 or 10, 0, 0),
  1094. Size = UDim2.new(1, -30, 1, 0),
  1095. Font = Enum.Font.GothamBold,
  1096. Text = secTitle:upper(),
  1097. TextColor3 = CurrentTheme.accent,
  1098. TextSize = 12,
  1099. TextXAlignment = Enum.TextXAlignment.Left,
  1100. Parent = sec
  1101. })
  1102.  
  1103. registerTheme(function(t)
  1104. bar.BackgroundColor3 = t.accent
  1105. titleS.TextColor3 = t.accent
  1106. if iconS then iconS.ImageColor3 = t.accent end
  1107. end)
  1108.  
  1109. return sec
  1110. end
  1111.  
  1112. -- ====================================================
  1113. -- ELEMENT CONTAINER HELPER
  1114. -- ====================================================
  1115. local function makeElementContainer(height)
  1116. local frame = create("Frame", {
  1117. BackgroundColor3 = CurrentTheme.bg3,
  1118. BackgroundTransparency = 0.35,
  1119. Size = UDim2.new(1, 0, 0, height or 42),
  1120. Parent = page
  1121. })
  1122. makeCorner(frame, 8)
  1123. makeStroke(frame, CurrentTheme.borderSoft, 1, 0.5)
  1124. return frame
  1125. end
  1126.  
  1127. -- ====================================================
  1128. -- TOGGLE
  1129. -- ====================================================
  1130. function Tab:CreateToggle(tOpts)
  1131. tOpts = tOpts or {}
  1132. local name = tOpts.Name or "Toggle"
  1133. local desc = tOpts.Description
  1134. local default = tOpts.Default or false
  1135. local flag = tOpts.Flag
  1136. local callback = tOpts.Callback or function() end
  1137.  
  1138. local h = desc and 52 or 40
  1139. local frame = makeElementContainer(h)
  1140. local value = default
  1141.  
  1142. local nameL = create("TextLabel", {
  1143. BackgroundTransparency = 1,
  1144. Position = UDim2.new(0, 12, 0, desc and 6 or 0),
  1145. Size = UDim2.new(1, -70, 0, 18),
  1146. Font = Enum.Font.GothamMedium,
  1147. Text = name,
  1148. TextColor3 = CurrentTheme.text,
  1149. TextSize = 13,
  1150. TextXAlignment = Enum.TextXAlignment.Left,
  1151. Parent = frame
  1152. })
  1153. if desc then
  1154. create("TextLabel", {
  1155. BackgroundTransparency = 1,
  1156. Position = UDim2.new(0, 12, 0, 26),
  1157. Size = UDim2.new(1, -70, 0, 16),
  1158. Font = fontBody,
  1159. Text = desc,
  1160. TextColor3 = CurrentTheme.text3,
  1161. TextSize = 11,
  1162. TextXAlignment = Enum.TextXAlignment.Left,
  1163. Parent = frame
  1164. })
  1165. end
  1166.  
  1167. local track = create("Frame", {
  1168. BackgroundColor3 = value and CurrentTheme.accent or CurrentTheme.bg4,
  1169. Position = UDim2.new(1, -48, 0.5, 0),
  1170. AnchorPoint = Vector2.new(0, 0.5),
  1171. Size = UDim2.fromOffset(36, 20),
  1172. Parent = frame
  1173. })
  1174. makeCorner(track, 10)
  1175.  
  1176. local thumb = create("Frame", {
  1177. BackgroundColor3 = Color3.fromRGB(255, 255, 255),
  1178. Position = value and UDim2.new(1, -18, 0.5, 0) or UDim2.new(0, 2, 0.5, 0),
  1179. AnchorPoint = Vector2.new(0, 0.5),
  1180. Size = UDim2.fromOffset(16, 16),
  1181. Parent = track
  1182. })
  1183. makeCorner(thumb, 8)
  1184.  
  1185. local function set(v, silent)
  1186. value = v
  1187. tween(track, { BackgroundColor3 = value and CurrentTheme.accent or CurrentTheme.bg4 }, 0.2)
  1188. tween(thumb, { Position = value and UDim2.new(1, -18, 0.5, 0) or UDim2.new(0, 2, 0.5, 0) }, 0.2)
  1189. if not silent then
  1190. pcall(callback, value)
  1191. end
  1192. end
  1193.  
  1194. local btn = create("TextButton", {
  1195. BackgroundTransparency = 1,
  1196. Size = UDim2.fromScale(1, 1),
  1197. Text = "",
  1198. Parent = frame
  1199. })
  1200. btn.MouseButton1Click:Connect(function() set(not value) end)
  1201.  
  1202. registerFlag(flag, function() return value end, function(v) set(v, true) end)
  1203. registerTheme(function(t)
  1204. nameL.TextColor3 = t.text
  1205. track.BackgroundColor3 = value and t.accent or t.bg4
  1206. frame.BackgroundColor3 = t.bg3
  1207. end)
  1208.  
  1209. local obj = {
  1210. SetValue = function(_, v) set(v) end,
  1211. GetValue = function() return value end,
  1212. SetVisible = function(_, v) frame.Visible = v end,
  1213. Destroy = function() frame:Destroy() end,
  1214. }
  1215. return obj
  1216. end
  1217.  
  1218. -- ====================================================
  1219. -- BUTTON
  1220. -- ====================================================
  1221. function Tab:CreateButton(bOpts)
  1222. bOpts = bOpts or {}
  1223. local name = bOpts.Name or "Button"
  1224. local desc = bOpts.Description
  1225. local icon = bOpts.Icon
  1226. local image = bOpts.Image
  1227. local color = bOpts.Color
  1228. local callback = bOpts.Callback or function() end
  1229.  
  1230. local h = desc and 52 or 40
  1231. local frame = makeElementContainer(h)
  1232. if color then frame.BackgroundColor3 = color end
  1233.  
  1234. if image then
  1235. create("ImageLabel", {
  1236. BackgroundTransparency = 1,
  1237. Size = UDim2.fromScale(1, 1),
  1238. Image = image,
  1239. ImageTransparency = 0.7,
  1240. ScaleType = Enum.ScaleType.Crop,
  1241. Parent = frame
  1242. })
  1243. end
  1244.  
  1245. local iconImgB = nil
  1246. if icon then
  1247. iconImgB = create("ImageLabel", {
  1248. BackgroundTransparency = 1,
  1249. Position = UDim2.new(0, 12, 0.5, 0),
  1250. AnchorPoint = Vector2.new(0, 0.5),
  1251. Size = UDim2.fromOffset(16, 16),
  1252. Parent = frame
  1253. })
  1254. applyIcon(iconImgB, icon, color and Color3.new(1,1,1) or CurrentTheme.accent)
  1255. end
  1256.  
  1257. local nameL = create("TextLabel", {
  1258. BackgroundTransparency = 1,
  1259. Position = UDim2.new(0, icon and 34 or 12, 0, desc and 6 or 0),
  1260. Size = UDim2.new(1, -20, 0, 18),
  1261. Font = Enum.Font.GothamMedium,
  1262. Text = name,
  1263. TextColor3 = CurrentTheme.text,
  1264. TextSize = 13,
  1265. TextXAlignment = Enum.TextXAlignment.Left,
  1266. Parent = frame
  1267. })
  1268. if desc then
  1269. create("TextLabel", {
  1270. BackgroundTransparency = 1,
  1271. Position = UDim2.new(0, icon and 34 or 12, 0, 26),
  1272. Size = UDim2.new(1, -20, 0, 16),
  1273. Font = fontBody,
  1274. Text = desc,
  1275. TextColor3 = CurrentTheme.text3,
  1276. TextSize = 11,
  1277. TextXAlignment = Enum.TextXAlignment.Left,
  1278. Parent = frame
  1279. })
  1280. end
  1281.  
  1282. local btn = create("TextButton", {
  1283. BackgroundTransparency = 1,
  1284. Size = UDim2.fromScale(1, 1),
  1285. Text = "",
  1286. Parent = frame
  1287. })
  1288.  
  1289. btn.MouseEnter:Connect(function()
  1290. tween(frame, { BackgroundTransparency = 0.15 }, 0.15)
  1291. end)
  1292. btn.MouseLeave:Connect(function()
  1293. tween(frame, { BackgroundTransparency = 0.35 }, 0.15)
  1294. end)
  1295. btn.MouseButton1Down:Connect(function()
  1296. tween(frame, { Size = UDim2.new(1, -4, 0, h - 2) }, 0.08)
  1297. end)
  1298. btn.MouseButton1Up:Connect(function()
  1299. tween(frame, { Size = UDim2.new(1, 0, 0, h) }, 0.1)
  1300. end)
  1301. btn.MouseButton1Click:Connect(function()
  1302. pcall(callback)
  1303. end)
  1304.  
  1305. registerTheme(function(t)
  1306. if not color then frame.BackgroundColor3 = t.bg3 end
  1307. nameL.TextColor3 = t.text
  1308. if iconImgB then iconImgB.ImageColor3 = t.accent end
  1309. end)
  1310.  
  1311. return {
  1312. SetVisible = function(_, v) frame.Visible = v end,
  1313. Destroy = function() frame:Destroy() end,
  1314. }
  1315. end
  1316.  
  1317. -- ====================================================
  1318. -- SLIDER
  1319. -- ====================================================
  1320. function Tab:CreateSlider(sOpts)
  1321. sOpts = sOpts or {}
  1322. local name = sOpts.Name or "Slider"
  1323. local min = sOpts.Min or 0
  1324. local max = sOpts.Max or 100
  1325. local default = sOpts.Default or min
  1326. local increment = sOpts.Increment or 1
  1327. local suffix = sOpts.Suffix or ""
  1328. local flag = sOpts.Flag
  1329. local callback = sOpts.Callback or function() end
  1330.  
  1331. local frame = makeElementContainer(56)
  1332. local value = clamp(default, min, max)
  1333.  
  1334. local nameL = create("TextLabel", {
  1335. BackgroundTransparency = 1,
  1336. Position = UDim2.new(0, 12, 0, 6),
  1337. Size = UDim2.new(0.6, 0, 0, 16),
  1338. Font = Enum.Font.GothamMedium,
  1339. Text = name,
  1340. TextColor3 = CurrentTheme.text,
  1341. TextSize = 13,
  1342. TextXAlignment = Enum.TextXAlignment.Left,
  1343. Parent = frame
  1344. })
  1345.  
  1346. local valueL = create("TextLabel", {
  1347. BackgroundTransparency = 1,
  1348. Position = UDim2.new(0.6, 0, 0, 6),
  1349. Size = UDim2.new(0.4, -12, 0, 16),
  1350. Font = Enum.Font.Gotham,
  1351. Text = tostring(value) .. suffix,
  1352. TextColor3 = CurrentTheme.accent,
  1353. TextSize = 12,
  1354. TextXAlignment = Enum.TextXAlignment.Right,
  1355. Parent = frame
  1356. })
  1357.  
  1358. local track = create("Frame", {
  1359. BackgroundColor3 = CurrentTheme.bg4,
  1360. Position = UDim2.new(0, 12, 0, 32),
  1361. Size = UDim2.new(1, -24, 0, 6),
  1362. Parent = frame
  1363. })
  1364. makeCorner(track, 3)
  1365.  
  1366. local fill = create("Frame", {
  1367. BackgroundColor3 = CurrentTheme.accent,
  1368. Size = UDim2.new((value - min) / (max - min), 0, 1, 0),
  1369. Parent = track
  1370. })
  1371. makeCorner(fill, 3)
  1372.  
  1373. local knob = create("Frame", {
  1374. BackgroundColor3 = Color3.fromRGB(255, 255, 255),
  1375. Size = UDim2.fromOffset(14, 14),
  1376. Position = UDim2.new((value - min) / (max - min), 0, 0.5, 0),
  1377. AnchorPoint = Vector2.new(0.5, 0.5),
  1378. Parent = track
  1379. })
  1380. makeCorner(knob, 7)
  1381.  
  1382. local function set(v, silent)
  1383. value = clamp(round(v, increment), min, max)
  1384. local pct = (value - min) / math.max(max - min, 0.001)
  1385. fill.Size = UDim2.new(pct, 0, 1, 0)
  1386. knob.Position = UDim2.new(pct, 0, 0.5, 0)
  1387. valueL.Text = tostring(value) .. suffix
  1388. if not silent then pcall(callback, value) end
  1389. end
  1390.  
  1391. local sliding = false
  1392. local function updateFromInput(input)
  1393. local rel = (input.Position.X - track.AbsolutePosition.X) / track.AbsoluteSize.X
  1394. set(min + rel * (max - min))
  1395. end
  1396.  
  1397. track.InputBegan:Connect(function(input)
  1398. if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
  1399. sliding = true
  1400. updateFromInput(input)
  1401. end
  1402. end)
  1403. UserInputService.InputEnded:Connect(function(input)
  1404. if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then
  1405. sliding = false
  1406. end
  1407. end)
  1408. UserInputService.InputChanged:Connect(function(input)
  1409. if sliding and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then
  1410. updateFromInput(input)
  1411. end
  1412. end)
  1413.  
  1414. registerFlag(flag, function() return value end, function(v) set(v, true) end)
  1415. registerTheme(function(t)
  1416. nameL.TextColor3 = t.text
  1417. valueL.TextColor3 = t.accent
  1418. fill.BackgroundColor3 = t.accent
  1419. frame.BackgroundColor3 = t.bg3
  1420. track.BackgroundColor3 = t.bg4
  1421. end)
  1422.  
  1423. return {
  1424. SetValue = function(_, v) set(v) end,
  1425. GetValue = function() return value end,
  1426. SetVisible = function(_, v) frame.Visible = v end,
  1427. Destroy = function() frame:Destroy() end,
  1428. }
  1429. end
  1430.  
  1431. -- ====================================================
  1432. -- DROPDOWN
  1433. -- ====================================================
  1434. function Tab:CreateDropdown(dOpts)
  1435. dOpts = dOpts or {}
  1436. local name = dOpts.Name or "Dropdown"
  1437. local options = dOpts.Options or {}
  1438. local default = dOpts.Default or 1
  1439. local multi = dOpts.Multi or false
  1440. local flag = dOpts.Flag
  1441. local callback = dOpts.Callback or function() end
  1442. local search = dOpts.Search
  1443.  
  1444. local frame = makeElementContainer(40)
  1445. local selected = multi and {} or (options[default] or options[1])
  1446. if multi and type(default) == "table" then selected = default end
  1447.  
  1448. local nameL = create("TextLabel", {
  1449. BackgroundTransparency = 1,
  1450. Position = UDim2.new(0, 12, 0, 0),
  1451. Size = UDim2.new(0.45, 0, 1, 0),
  1452. Font = Enum.Font.GothamMedium,
  1453. Text = name,
  1454. TextColor3 = CurrentTheme.text,
  1455. TextSize = 13,
  1456. TextXAlignment = Enum.TextXAlignment.Left,
  1457. Parent = frame
  1458. })
  1459.  
  1460. local display = create("TextLabel", {
  1461. BackgroundTransparency = 1,
  1462. Position = UDim2.new(0.45, 0, 0, 0),
  1463. Size = UDim2.new(0.45, 0, 1, 0),
  1464. Font = fontBody,
  1465. Text = multi and (table.concat(selected, ", ") or "None") or tostring(selected),
  1466. TextColor3 = CurrentTheme.text2,
  1467. TextSize = 12,
  1468. TextXAlignment = Enum.TextXAlignment.Right,
  1469. TextTruncate = Enum.TextTruncate.AtEnd,
  1470. Parent = frame
  1471. })
  1472.  
  1473. local arrow = create("TextLabel", {
  1474. BackgroundTransparency = 1,
  1475. Position = UDim2.new(1, -24, 0, 0),
  1476. Size = UDim2.fromOffset(20, 40),
  1477. Font = Enum.Font.GothamBold,
  1478. Text = "▾",
  1479. TextColor3 = CurrentTheme.text3,
  1480. TextSize = 12,
  1481. Parent = frame
  1482. })
  1483.  
  1484. local dropFrame = create("Frame", {
  1485. BackgroundColor3 = CurrentTheme.bg2,
  1486. Size = UDim2.new(1, 0, 0, 0),
  1487. Position = UDim2.new(0, 0, 1, 4),
  1488. Visible = false,
  1489. ClipsDescendants = true,
  1490. ZIndex = 20,
  1491. Parent = frame
  1492. })
  1493. makeCorner(dropFrame, 8)
  1494. makeStroke(dropFrame, CurrentTheme.border, 1, 0.4)
  1495. local dropList = create("ScrollingFrame", {
  1496. BackgroundTransparency = 1,
  1497. Size = UDim2.fromScale(1, 1),
  1498. CanvasSize = UDim2.new(0, 0, 0, 0),
  1499. ScrollBarThickness = 3,
  1500. BorderSizePixel = 0,
  1501. ZIndex = 21,
  1502. Parent = dropFrame
  1503. })
  1504. makeList(dropList, 2)
  1505. makePadding(dropList, 4, 4, 4, 4)
  1506.  
  1507. local open = false
  1508. local function refreshDisplay()
  1509. if multi then
  1510. display.Text = #selected > 0 and table.concat(selected, ", ") or "None"
  1511. else
  1512. display.Text = tostring(selected)
  1513. end
  1514. end
  1515.  
  1516. local function toggleDrop()
  1517. open = not open
  1518. dropFrame.Visible = open
  1519. if open then
  1520. local h = math.min(#options * 28 + 8, 160)
  1521. tween(dropFrame, { Size = UDim2.new(1, 0, 0, h) }, 0.2)
  1522. frame.ZIndex = 10
  1523. else
  1524. tween(dropFrame, { Size = UDim2.new(1, 0, 0, 0) }, 0.15)
  1525. task.delay(0.15, function()
  1526. if not open then dropFrame.Visible = false; frame.ZIndex = 1 end
  1527. end)
  1528. end
  1529. end
  1530.  
  1531. local function buildOptions()
  1532. for _, c in ipairs(dropList:GetChildren()) do
  1533. if c:IsA("TextButton") then c:Destroy() end
  1534. end
  1535. for i, opt in ipairs(options) do
  1536. local optBtn = create("TextButton", {
  1537. BackgroundColor3 = CurrentTheme.bg3,
  1538. BackgroundTransparency = 0.5,
  1539. Size = UDim2.new(1, -8, 0, 26),
  1540. Text = " " .. tostring(opt),
  1541. Font = fontBody,
  1542. TextSize = 12,
  1543. TextColor3 = CurrentTheme.text,
  1544. TextXAlignment = Enum.TextXAlignment.Left,
  1545. AutoButtonColor = false,
  1546. ZIndex = 22,
  1547. Parent = dropList
  1548. })
  1549. makeCorner(optBtn, 5)
  1550. optBtn.MouseEnter:Connect(function()
  1551. tween(optBtn, { BackgroundTransparency = 0.2 }, 0.1)
  1552. end)
  1553. optBtn.MouseLeave:Connect(function()
  1554. tween(optBtn, { BackgroundTransparency = 0.5 }, 0.1)
  1555. end)
  1556. optBtn.MouseButton1Click:Connect(function()
  1557. if multi then
  1558. local idx = table.find(selected, opt)
  1559. if idx then table.remove(selected, idx) else table.insert(selected, opt) end
  1560. refreshDisplay()
  1561. pcall(callback, selected)
  1562. else
  1563. selected = opt
  1564. refreshDisplay()
  1565. toggleDrop()
  1566. pcall(callback, selected)
  1567. end
  1568. end)
  1569. end
  1570. dropList.CanvasSize = UDim2.new(0, 0, 0, #options * 28 + 8)
  1571. end
  1572. buildOptions()
  1573.  
  1574. local clickBtn = create("TextButton", {
  1575. BackgroundTransparency = 1,
  1576. Size = UDim2.fromScale(1, 1),
  1577. Text = "",
  1578. ZIndex = 5,
  1579. Parent = frame
  1580. })
  1581. clickBtn.MouseButton1Click:Connect(toggleDrop)
  1582.  
  1583. registerFlag(flag, function() return selected end, function(v)
  1584. selected = v
  1585. refreshDisplay()
  1586. end)
  1587. registerTheme(function(t)
  1588. nameL.TextColor3 = t.text
  1589. display.TextColor3 = t.text2
  1590. frame.BackgroundColor3 = t.bg3
  1591. dropFrame.BackgroundColor3 = t.bg2
  1592. end)
  1593.  
  1594. return {
  1595. SetValue = function(_, v) selected = v; refreshDisplay() end,
  1596. GetValue = function() return selected end,
  1597. SetOptions = function(_, opts) options = opts; buildOptions() end,
  1598. SetVisible = function(_, v) frame.Visible = v end,
  1599. Destroy = function() frame:Destroy() end,
  1600. }
  1601. end
  1602.  
  1603. -- ====================================================
  1604. -- INPUT
  1605. -- ====================================================
  1606. function Tab:CreateInput(iOpts)
  1607. iOpts = iOpts or {}
  1608. local name = iOpts.Name or "Input"
  1609. local placeholder = iOpts.Placeholder or ""
  1610. local default = iOpts.Default or ""
  1611. local numeric = iOpts.Numeric
  1612. local flag = iOpts.Flag
  1613. local callback = iOpts.Callback or function() end
  1614.  
  1615. local frame = makeElementContainer(40)
  1616.  
  1617. create("TextLabel", {
  1618. BackgroundTransparency = 1,
  1619. Position = UDim2.new(0, 12, 0, 0),
  1620. Size = UDim2.new(0.35, 0, 1, 0),
  1621. Font = Enum.Font.GothamMedium,
  1622. Text = name,
  1623. TextColor3 = CurrentTheme.text,
  1624. TextSize = 13,
  1625. TextXAlignment = Enum.TextXAlignment.Left,
  1626. Parent = frame
  1627. })
  1628.  
  1629. local box = create("TextBox", {
  1630. BackgroundColor3 = CurrentTheme.bg4,
  1631. Position = UDim2.new(0.38, 0, 0.5, 0),
  1632. AnchorPoint = Vector2.new(0, 0.5),
  1633. Size = UDim2.new(0.58, 0, 0, 26),
  1634. Font = fontBody,
  1635. Text = default,
  1636. PlaceholderText = placeholder,
  1637. PlaceholderColor3 = CurrentTheme.text3,
  1638. TextColor3 = CurrentTheme.text,
  1639. TextSize = 12,
  1640. ClearTextOnFocus = false,
  1641. Parent = frame
  1642. })
  1643. makeCorner(box, 6)
  1644. makePadding(box, 0, 0, 8, 8)
  1645.  
  1646. box.FocusLost:Connect(function(enter)
  1647. local txt = box.Text
  1648. if numeric then
  1649. txt = tonumber(txt) or 0
  1650. box.Text = tostring(txt)
  1651. end
  1652. pcall(callback, txt)
  1653. end)
  1654.  
  1655. registerFlag(flag, function() return box.Text end, function(v) box.Text = tostring(v) end)
  1656. registerTheme(function(t)
  1657. box.BackgroundColor3 = t.bg4
  1658. box.TextColor3 = t.text
  1659. box.PlaceholderColor3 = t.text3
  1660. frame.BackgroundColor3 = t.bg3
  1661. end)
  1662.  
  1663. return {
  1664. SetValue = function(_, v) box.Text = tostring(v) end,
  1665. GetValue = function() return box.Text end,
  1666. SetVisible = function(_, v) frame.Visible = v end,
  1667. Destroy = function() frame:Destroy() end,
  1668. }
  1669. end
  1670.  
  1671. -- ====================================================
  1672. -- KEYBIND
  1673. -- ====================================================
  1674. function Tab:CreateKeybind(kOpts)
  1675. kOpts = kOpts or {}
  1676. local name = kOpts.Name or "Keybind"
  1677. local default = kOpts.Default or Enum.KeyCode.E
  1678. local flag = kOpts.Flag
  1679. local callback = kOpts.Callback or function() end
  1680.  
  1681. local frame = makeElementContainer(40)
  1682. local current = default
  1683. local listening = false
  1684.  
  1685. create("TextLabel", {
  1686. BackgroundTransparency = 1,
  1687. Position = UDim2.new(0, 12, 0, 0),
  1688. Size = UDim2.new(0.5, 0, 1, 0),
  1689. Font = Enum.Font.GothamMedium,
  1690. Text = name,
  1691. TextColor3 = CurrentTheme.text,
  1692. TextSize = 13,
  1693. TextXAlignment = Enum.TextXAlignment.Left,
  1694. Parent = frame
  1695. })
  1696.  
  1697. local keyBtn = create("TextButton", {
  1698. BackgroundColor3 = CurrentTheme.bg4,
  1699. Position = UDim2.new(1, -100, 0.5, 0),
  1700. AnchorPoint = Vector2.new(0, 0.5),
  1701. Size = UDim2.fromOffset(88, 26),
  1702. Font = fontBody,
  1703. Text = current.Name,
  1704. TextColor3 = CurrentTheme.accent,
  1705. TextSize = 12,
  1706. AutoButtonColor = false,
  1707. Parent = frame
  1708. })
  1709. makeCorner(keyBtn, 6)
  1710.  
  1711. keyBtn.MouseButton1Click:Connect(function()
  1712. listening = true
  1713. keyBtn.Text = "..."
  1714. end)
  1715.  
  1716. UserInputService.InputBegan:Connect(function(input, gpe)
  1717. if not listening then return end
  1718. if input.UserInputType == Enum.UserInputType.Keyboard then
  1719. current = input.KeyCode
  1720. keyBtn.Text = current.Name
  1721. listening = false
  1722. pcall(callback, current)
  1723. end
  1724. end)
  1725.  
  1726. registerFlag(flag, function() return current end, function(v)
  1727. current = v
  1728. keyBtn.Text = current.Name
  1729. end)
  1730. registerTheme(function(t)
  1731. keyBtn.BackgroundColor3 = t.bg4
  1732. keyBtn.TextColor3 = t.accent
  1733. frame.BackgroundColor3 = t.bg3
  1734. end)
  1735.  
  1736. return {
  1737. SetValue = function(_, v) current = v; keyBtn.Text = v.Name end,
  1738. GetValue = function() return current end,
  1739. SetVisible = function(_, v) frame.Visible = v end,
  1740. Destroy = function() frame:Destroy() end,
  1741. }
  1742. end
  1743.  
  1744. -- ====================================================
  1745. -- PARAGRAPH / LABEL
  1746. -- ====================================================
  1747. function Tab:CreateParagraph(pOpts)
  1748. pOpts = pOpts or {}
  1749. local title = pOpts.Title or ""
  1750. local content = pOpts.Content or ""
  1751.  
  1752. local frame = create("Frame", {
  1753. BackgroundColor3 = CurrentTheme.bg3,
  1754. BackgroundTransparency = 0.4,
  1755. Size = UDim2.new(1, 0, 0, 0),
  1756. Parent = page
  1757. })
  1758. makeCorner(frame, 8)
  1759. makePadding(frame, 10, 10, 12, 12)
  1760.  
  1761. local tL = create("TextLabel", {
  1762. BackgroundTransparency = 1,
  1763. Size = UDim2.new(1, 0, 0, 16),
  1764. Font = Enum.Font.GothamBold,
  1765. Text = title,
  1766. TextColor3 = CurrentTheme.accent,
  1767. TextSize = 12,
  1768. TextXAlignment = Enum.TextXAlignment.Left,
  1769. Parent = frame
  1770. })
  1771. local cL = create("TextLabel", {
  1772. BackgroundTransparency = 1,
  1773. Position = UDim2.new(0, 0, 0, 20),
  1774. Size = UDim2.new(1, 0, 0, 0),
  1775. Font = fontBody,
  1776. Text = content,
  1777. TextColor3 = CurrentTheme.text2,
  1778. TextSize = 12,
  1779. TextXAlignment = Enum.TextXAlignment.Left,
  1780. TextWrapped = true,
  1781. Parent = frame
  1782. })
  1783. cL.Size = UDim2.new(1, 0, 0, cL.TextBounds.Y + 4)
  1784. frame.Size = UDim2.new(1, 0, 0, 36 + cL.TextBounds.Y)
  1785.  
  1786. registerTheme(function(t)
  1787. tL.TextColor3 = t.accent
  1788. cL.TextColor3 = t.text2
  1789. frame.BackgroundColor3 = t.bg3
  1790. end)
  1791.  
  1792. return {
  1793. SetVisible = function(_, v) frame.Visible = v end,
  1794. Destroy = function() frame:Destroy() end,
  1795. }
  1796. end
  1797.  
  1798. function Tab:CreateLabel(lOpts)
  1799. lOpts = lOpts or {}
  1800. local text = lOpts.Text or "Label"
  1801. local gradient = lOpts.Gradient
  1802.  
  1803. local frame = create("Frame", {
  1804. BackgroundTransparency = 1,
  1805. Size = UDim2.new(1, 0, 0, 22),
  1806. Parent = page
  1807. })
  1808. local lbl = create("TextLabel", {
  1809. BackgroundTransparency = 1,
  1810. Size = UDim2.fromScale(1, 1),
  1811. Font = Enum.Font.GothamMedium,
  1812. Text = text,
  1813. TextColor3 = CurrentTheme.text,
  1814. TextSize = 13,
  1815. TextXAlignment = Enum.TextXAlignment.Left,
  1816. Parent = frame
  1817. })
  1818. if gradient then
  1819. local g = create("UIGradient", {
  1820. Color = ColorSequence.new({
  1821. ColorSequenceKeypoint.new(0, CurrentTheme.accent),
  1822. ColorSequenceKeypoint.new(1, CurrentTheme.accent3),
  1823. }),
  1824. Parent = lbl
  1825. })
  1826. registerTheme(function(t)
  1827. g.Color = ColorSequence.new({
  1828. ColorSequenceKeypoint.new(0, t.accent),
  1829. ColorSequenceKeypoint.new(1, t.accent3),
  1830. })
  1831. end)
  1832. else
  1833. registerTheme(function(t) lbl.TextColor3 = t.text end)
  1834. end
  1835.  
  1836. return {
  1837. SetText = function(_, t) lbl.Text = t end,
  1838. SetVisible = function(_, v) frame.Visible = v end,
  1839. Destroy = function() frame:Destroy() end,
  1840. }
  1841. end
  1842.  
  1843. -- ====================================================
  1844. -- DIVIDER
  1845. -- ====================================================
  1846. function Tab:CreateDivider()
  1847. local frame = create("Frame", {
  1848. BackgroundTransparency = 1,
  1849. Size = UDim2.new(1, 0, 0, 12),
  1850. Parent = page
  1851. })
  1852. local line = create("Frame", {
  1853. BackgroundColor3 = CurrentTheme.borderSoft,
  1854. AnchorPoint = Vector2.new(0.5, 0.5),
  1855. Position = UDim2.fromScale(0.5, 0.5),
  1856. Size = UDim2.new(1, 0, 0, 1),
  1857. Parent = frame
  1858. })
  1859. registerTheme(function(t) line.BackgroundColor3 = t.borderSoft end)
  1860. return frame
  1861. end
  1862.  
  1863. -- ====================================================
  1864. -- COLOR PICKER (simple)
  1865. -- ====================================================
  1866. function Tab:CreateColorPicker(cOpts)
  1867. cOpts = cOpts or {}
  1868. local name = cOpts.Name or "Color"
  1869. local default = cOpts.Default or Color3.fromRGB(255, 255, 255)
  1870. local flag = cOpts.Flag
  1871. local callback = cOpts.Callback or function() end
  1872.  
  1873. local frame = makeElementContainer(40)
  1874. local value = default
  1875.  
  1876. create("TextLabel", {
  1877. BackgroundTransparency = 1,
  1878. Position = UDim2.new(0, 12, 0, 0),
  1879. Size = UDim2.new(0.6, 0, 1, 0),
  1880. Font = Enum.Font.GothamMedium,
  1881. Text = name,
  1882. TextColor3 = CurrentTheme.text,
  1883. TextSize = 13,
  1884. TextXAlignment = Enum.TextXAlignment.Left,
  1885. Parent = frame
  1886. })
  1887.  
  1888. local preview = create("Frame", {
  1889. BackgroundColor3 = value,
  1890. Position = UDim2.new(1, -40, 0.5, 0),
  1891. AnchorPoint = Vector2.new(0, 0.5),
  1892. Size = UDim2.fromOffset(28, 28),
  1893. Parent = frame
  1894. })
  1895. makeCorner(preview, 6)
  1896. makeStroke(preview, CurrentTheme.border, 1, 0.3)
  1897.  
  1898. -- Simple cycle / click to open is complex; provide SetValue primarily
  1899. -- For full picker would need HSV wheel — keep lightweight
  1900. local btn = create("TextButton", {
  1901. BackgroundTransparency = 1,
  1902. Size = UDim2.fromScale(1, 1),
  1903. Text = "",
  1904. Parent = frame
  1905. })
  1906. -- Basic: user can SetValue externally; click does nothing heavy
  1907.  
  1908. registerFlag(flag, function() return value end, function(v)
  1909. value = v
  1910. preview.BackgroundColor3 = v
  1911. end)
  1912. registerTheme(function(t) frame.BackgroundColor3 = t.bg3 end)
  1913.  
  1914. return {
  1915. SetValue = function(_, v) value = v; preview.BackgroundColor3 = v; pcall(callback, v) end,
  1916. GetValue = function() return value end,
  1917. SetVisible = function(_, v) frame.Visible = v end,
  1918. Destroy = function() frame:Destroy() end,
  1919. }
  1920. end
  1921.  
  1922. -- ====================================================
  1923. -- PLAYER SELECTOR
  1924. -- ====================================================
  1925. function Tab:CreatePlayerSelector(pOpts)
  1926. pOpts = pOpts or {}
  1927. local name = pOpts.Name or "Player"
  1928. local multi = pOpts.Multi or false
  1929. local flag = pOpts.Flag
  1930. local callback = pOpts.Callback or function() end
  1931.  
  1932. local options = {}
  1933. for _, p in ipairs(Players:GetPlayers()) do
  1934. if p ~= LocalPlayer then
  1935. table.insert(options, p.Name)
  1936. end
  1937. end
  1938.  
  1939. local dd = Tab:CreateDropdown({
  1940. Name = name,
  1941. Options = options,
  1942. Multi = multi,
  1943. Flag = flag,
  1944. Callback = callback,
  1945. })
  1946.  
  1947. -- Refresh button via small extra
  1948. return dd
  1949. end
  1950.  
  1951. return Tab
  1952. end
  1953.  
  1954. table.insert(Windows, Window)
  1955.  
  1956. -- Reveal after loading
  1957. if loadingScreen then
  1958. task.delay(1.2, function()
  1959. main.Visible = true
  1960. main.Size = UDim2.fromOffset(0, 0)
  1961. tween(main, { Size = finalSize }, 0.4, Enum.EasingStyle.Back)
  1962. end)
  1963. end
  1964.  
  1965. return Window
  1966. end
  1967.  
  1968. -- Global notify alias
  1969. EchelonUI.Notify = function(_, opts)
  1970. EchelonUI:Notify(opts)
  1971. end
  1972.  
  1973. --[[
  1974. ============================================================
  1975. EXAMPLE USAGE (remove or comment in production)
  1976. ============================================================
  1977. local Lib = EchelonUI
  1978. local Win = Lib:CreateWindow({
  1979. Title = "ECHELON HUB",
  1980. SubTitle = "1.0",
  1981. Theme = "Aqua",
  1982. Logo = nil,
  1983. })
  1984.  
  1985. local T = Win:CreateTab({ Name = "Main", Icon = "house" })
  1986. T:CreateSection({ Title = "General", Icon = "settings" })
  1987. T:CreateToggle({
  1988. Name = "Enabled",
  1989. Description = "Turn on feature",
  1990. Default = false,
  1991. Flag = "Enabled",
  1992. Callback = function(v) print("Toggle:", v) end,
  1993. })
  1994. T:CreateButton({
  1995. Name = "Click Me",
  1996. Icon = "mouse-pointer-click",
  1997. Callback = function()
  1998. Win:Notify({ Title = "OK", Content = "Clicked successfully", Type = "Success" })
  1999. end,
  2000. })
  2001. T:CreateSlider({
  2002. Name = "WalkSpeed",
  2003. Min = 16, Max = 100, Default = 16,
  2004. Flag = "WS",
  2005. Callback = function(v) print(v) end,
  2006. })
  2007. T:CreateDropdown({
  2008. Name = "Mode",
  2009. Options = {"Safe", "Normal", "Rage"},
  2010. Default = 2,
  2011. Flag = "Mode",
  2012. Callback = print,
  2013. })
  2014. T:CreateInput({ Name = "Config", Placeholder = "name", Flag = "Cfg" })
  2015. T:CreateKeybind({ Name = "Key", Default = Enum.KeyCode.Q, Flag = "Key" })
  2016. T:CreateLabel({ Text = "Status: Ready", Gradient = true })
  2017. T:CreateParagraph({ Title = "Info", Content = "EchelonUI v1.0 — Premium dark cyber library." })
  2018. T:CreateDivider()
  2019. ]]
  2020.  
  2021. return EchelonUI