From ce77ce0e9f4041b30412e36a387b4f596dd66b4e Mon Sep 17 00:00:00 2001 From: Sxmple Date: Thu, 13 Aug 2026 14:05:59 +0300 Subject: [PATCH 1/3] Refactor WindUI initialization and input handling --- src/Init.lua | 561 +++++++++++++++++++++------------------------------ 1 file changed, 235 insertions(+), 326 deletions(-) diff --git a/src/Init.lua b/src/Init.lua index 2a63d4b3..3a9f7627 100644 --- a/src/Init.lua +++ b/src/Init.lua @@ -1,35 +1,25 @@ local WindUI = { - Window = nil, - Theme = nil, - Creator = require("./modules/Creator"), - LocalizationModule = require("./modules/Localization"), - NotificationModule = require("./components/Notification"), - Themes = nil, - Transparent = false, - - TransparencyValue = 0.15, - - UIScale = 1, - - ConfigManager = nil, - Version = "0.0.0", - - Services = require("./utils/services/Init"), - - OnThemeChangeFunction = nil, - - cloneref = nil, - UIScaleObj = nil, - - CreateWindow = nil, - - CurrentInput = nil, + Window = nil, + Theme = nil, + Creator = require("./modules/Creator"), + LocalizationModule = require("./modules/Localization"), + NotificationModule = require("./components/Notification"), + Themes = nil, + Transparent = false, + TransparencyValue = 0.15, + UIScale = 1, + ConfigManager = nil, + Version = "0.0.0", + Services = require("./utils/services/Init"), + OnThemeChangeFunction = nil, + cloneref = nil, + UIScaleObj = nil, + CreateWindow = nil, + CurrentInput = nil, + RegisteredElements = {}, } -local cloneref = (cloneref or clonereference or function(instance) - return instance -end) - +local cloneref = (cloneref or clonereference or function(instance) return instance end) WindUI.cloneref = cloneref local HttpService = cloneref(game:GetService("HttpService")) @@ -39,112 +29,97 @@ local RunService = cloneref(game:GetService("RunService")) local UserInputService = cloneref(game:GetService("UserInputService")) function WindUI.GenerateGUID() - return HttpService:GenerateGUID(false) + return HttpService:GenerateGUID(false) end local CurInput = WindUI.GenerateGUID() UserInputService.InputBegan:Connect(function(Input, GameProcessed) - --[[if GameProcessed then - return - end]] - - task.defer(function() - if - Input.UserInputType == Enum.UserInputType.MouseButton1 - or Input.UserInputType == Enum.UserInputType.Touch - then - if WindUI.CurrentInput and WindUI.CurrentInput ~= CurInput then - return - end - - WindUI.CurrentInput = CurInput - --print(CurInput) - --WindUI.InputStartedOnUI = false - end - end) + --[[if GameProcessed then return end]] + task.defer(function() + if Input.UserInputType == Enum.UserInputType.MouseButton1 or Input.UserInputType == Enum.UserInputType.Touch then + if WindUI.CurrentInput and WindUI.CurrentInput ~= CurInput then return end + WindUI.CurrentInput = CurInput + --print(CurInput) + --WindUI.InputStartedOnUI = false + end + end) end) -UserInputService.InputEnded:Connect(function(Input, GameProcessed) - if Input.UserInputType == Enum.UserInputType.MouseButton1 or Input.UserInputType == Enum.UserInputType.Touch then - if WindUI.CurrentInput and WindUI.CurrentInput ~= CurInput then - return - end - WindUI.CurrentInput = nil - end +UserInputService.InputEnded:Connect(function(Input, GameProcessed) + if Input.UserInputType == Enum.UserInputType.MouseButton1 or Input.UserInputType == Enum.UserInputType.Touch then + if WindUI.CurrentInput and WindUI.CurrentInput ~= CurInput then return end + WindUI.CurrentInput = nil + end end) local LocalPlayer = Players.LocalPlayer or nil - local Package = HttpService:JSONDecode(require("../build/package")) + if Package then - WindUI.Version = Package.version + WindUI.Version = Package.version end local KeySystem = require("./components/KeySystem") - local Creator = WindUI.Creator - local New = Creator.New - --local Tween = Creator.Tween --local ServicesModule = WindUI.Services local Acrylic = require("./utils/Acrylic/Init") - local ProtectGui = protectgui or (syn and syn.protect_gui) or function() end - local GUIParent = gethui and gethui() or (CoreGui or LocalPlayer:WaitForChild("PlayerGui")) local UIScaleObj = New("UIScale", { - Scale = WindUI.UIScale, + Scale = WindUI.UIScale, }) - WindUI.UIScaleObj = UIScaleObj WindUI.ScreenGui = New("ScreenGui", { - Name = "WindUI", - Parent = GUIParent, - IgnoreGuiInset = true, - ScreenInsets = "None", - DisplayOrder = -99999, + Name = "WindUI", + Parent = GUIParent, + IgnoreGuiInset = true, + ScreenInsets = "None", + DisplayOrder = -99999, }, { - - New("Folder", { - Name = "Window", - }), - -- New("Folder", { - -- Name = "Notifications" - -- }), - -- New("Folder", { - -- Name = "Dropdowns" - -- }), - New("Folder", { - Name = "KeySystem", - }), - New("Folder", { - Name = "Popups", - }), - New("Folder", { - Name = "ToolTips", - }), + New("Folder", { + Name = "Window", + }), + -- New("Folder", { + -- Name = "Notifications" + -- }), + -- New("Folder", { + -- Name = "Dropdowns" + -- }), + New("Folder", { + Name = "KeySystem", + }), + New("Folder", { + Name = "Popups", + }), + New("Folder", { + Name = "ToolTips", + }), }) WindUI.NotificationGui = New("ScreenGui", { - Name = "WindUI/Notifications", - Parent = GUIParent, - IgnoreGuiInset = true, + Name = "WindUI/Notifications", + Parent = GUIParent, + IgnoreGuiInset = true, }) + WindUI.DropdownGui = New("ScreenGui", { - Name = "WindUI/Dropdowns", - Parent = GUIParent, - IgnoreGuiInset = true, + Name = "WindUI/Dropdowns", + Parent = GUIParent, + IgnoreGuiInset = true, }) + WindUI.TooltipGui = New("ScreenGui", { - Name = "WindUI/Tooltips", - Parent = GUIParent, - IgnoreGuiInset = true, + Name = "WindUI/Tooltips", + Parent = GUIParent, + IgnoreGuiInset = true, }) + ProtectGui(WindUI.ScreenGui) ProtectGui(WindUI.NotificationGui) ProtectGui(WindUI.DropdownGui) @@ -153,287 +128,221 @@ ProtectGui(WindUI.TooltipGui) Creator.Init(WindUI) function WindUI:SetParent(parent) - if WindUI.ScreenGui then - WindUI.ScreenGui.Parent = parent - end - if WindUI.NotificationGui then - WindUI.NotificationGui.Parent = parent - end - if WindUI.DropdownGui then - WindUI.DropdownGui.Parent = parent - end - if WindUI.TooltipGui then - WindUI.TooltipGui.Parent = parent - end + if WindUI.ScreenGui then WindUI.ScreenGui.Parent = parent end + if WindUI.NotificationGui then WindUI.NotificationGui.Parent = parent end + if WindUI.DropdownGui then WindUI.DropdownGui.Parent = parent end + if WindUI.TooltipGui then WindUI.TooltipGui.Parent = parent end end + math.clamp(WindUI.TransparencyValue, 0, 1) local Holder = WindUI.NotificationModule.Init(WindUI.NotificationGui) function WindUI:Notify(Config) - Config.Holder = Holder.Frame - Config.Window = WindUI.Window - --Config.WindUI = WindUI - return WindUI.NotificationModule.New(Config) + Config.Holder = Holder.Frame + Config.Window = WindUI.Window + --Config.WindUI = WindUI + return WindUI.NotificationModule.New(Config) end function WindUI:SetNotificationLower(Val) - Holder.SetLower(Val) + Holder.SetLower(Val) end function WindUI:SetFont(FontId) - Creator.UpdateFont(FontId) + Creator.UpdateFont(FontId) end function WindUI:OnThemeChange(func) - WindUI.OnThemeChangeFunction = func + WindUI.OnThemeChangeFunction = func end function WindUI:AddTheme(LTheme) - WindUI.Themes[LTheme.Name] = LTheme - return LTheme + WindUI.Themes[LTheme.Name] = LTheme + return LTheme end function WindUI:SetTheme(Value) - if WindUI.Themes[Value] then - WindUI.Theme = WindUI.Themes[Value] - Creator.SetTheme(WindUI.Themes[Value]) - - if WindUI.OnThemeChangeFunction then - WindUI.OnThemeChangeFunction(Value) - end - - return WindUI.Themes[Value] - end - return nil + if WindUI.Themes[Value] then + WindUI.Theme = WindUI.Themes[Value] + Creator.SetTheme(WindUI.Themes[Value]) + if WindUI.OnThemeChangeFunction then + WindUI.OnThemeChangeFunction(Value) + end + return WindUI.Themes[Value] + end + return nil end function WindUI:GetThemes() - return WindUI.Themes + return WindUI.Themes end + function WindUI:GetCurrentTheme() - return WindUI.Theme.Name + return WindUI.Theme.Name end + function WindUI:GetTransparency() - return WindUI.Transparent or false + return WindUI.Transparent or false end + function WindUI:GetWindowSize() - return WindUI.Window.UIElements.Main.Size + return WindUI.Window.UIElements.Main.Size end + function WindUI:Localization(LocalizationConfig) - return WindUI.LocalizationModule:New(LocalizationConfig, Creator) + return WindUI.LocalizationModule:New(LocalizationConfig, Creator) end function WindUI:SetLanguage(Value) - if Creator.Localization then - return Creator.SetLanguage(Value) - end - return false + if Creator.Localization then + return Creator.SetLanguage(Value) + end + return false end function WindUI:ToggleAcrylic(Value) - if WindUI.Window and WindUI.Window.AcrylicPaint and WindUI.Window.AcrylicPaint.Model then - WindUI.Window.Acrylic = Value - WindUI.Window.AcrylicPaint.Model.Transparency = Value and 0.98 or 1 - if Value then - Acrylic.Enable() - else - Acrylic.Disable() - end - end + if WindUI.Window and WindUI.Window.AcrylicPaint and WindUI.Window.AcrylicPaint.Model then + WindUI.Window.Acrylic = Value + WindUI.Window.AcrylicPaint.Model.Transparency = Value and 0.98 or 1 + if Value then + Acrylic.Enable() + else + Acrylic.Disable() + end + end end function WindUI:Gradient(stops, props) - local colorSequence = {} - local transparencySequence = {} - - for posStr, stop in next, stops do - local position = tonumber(posStr) - if position then - position = math.clamp(position / 100, 0, 1) - - local color = stop.Color - if typeof(color) == "string" and string.sub(color, 1, 1) == "#" then - color = Color3.fromHex(color) - end - - local transparency = stop.Transparency or 0 - - table.insert(colorSequence, ColorSequenceKeypoint.new(position, color)) - table.insert(transparencySequence, NumberSequenceKeypoint.new(position, transparency)) - end - end - - table.sort(colorSequence, function(a, b) - return a.Time < b.Time - end) - table.sort(transparencySequence, function(a, b) - return a.Time < b.Time - end) - - if #colorSequence < 2 then - table.insert(colorSequence, ColorSequenceKeypoint.new(1, colorSequence[1].Value)) - table.insert(transparencySequence, NumberSequenceKeypoint.new(1, transparencySequence[1].Value)) - end - - local gradientData = { - Color = ColorSequence.new(colorSequence), - Transparency = NumberSequence.new(transparencySequence), - } - - if props then - for k, v in pairs(props) do - gradientData[k] = v - end - end - - return gradientData + local colorSequence = {} + local transparencySequence = {} + for posStr, stop in next, stops do + local position = tonumber(posStr) + if position then + position = math.clamp(position / 100, 0, 1) + local color = stop.Color + if typeof(color) == "string" and string.sub(color, 1, 1) == "#" then + color = Color3.fromHex(color) + end + local transparency = stop.Transparency or 0 + table.insert(colorSequence, ColorSequenceKeypoint.new(position, color)) + table.insert(transparencySequence, NumberSequenceKeypoint.new(position, transparency)) + end + end + table.sort(colorSequence, function(a, b) return a.Time < b.Time end) + table.sort(transparencySequence, function(a, b) return a.Time < b.Time end) + if #colorSequence < 2 then + table.insert(colorSequence, ColorSequenceKeypoint.new(1, colorSequence[1].Value)) + table.insert(transparencySequence, NumberSequenceKeypoint.new(1, transparencySequence[1].Value)) + end + local gradientData = { + Color = ColorSequence.new(colorSequence), + Transparency = NumberSequence.new(transparencySequence), + } + if props then + for k, v in pairs(props) do gradientData[k] = v end + end + return gradientData end function WindUI:Popup(PopupConfig) - PopupConfig.WindUI = WindUI - return require("./components/popup/Init").new(PopupConfig, WindUI.ScreenGui.Popups) + PopupConfig.WindUI = WindUI + return require("./components/popup/Init").new(PopupConfig, WindUI.ScreenGui.Popups) end -WindUI.Themes = require("./themes/Init")(WindUI, Creator) +function WindUI:RegisterElement(ElementConfig) + if type(ElementConfig) == "string" then + return function(constructor) + WindUI.RegisteredElements[ElementConfig] = { + Name = ElementConfig, + Create = constructor + } + end + elseif type(ElementConfig) == "table" then + WindUI.RegisteredElements[ElementConfig.Name] = ElementConfig + return ElementConfig + end +end +WindUI.Themes = require("./themes/Init")(WindUI, Creator) Creator.Themes = WindUI.Themes - WindUI:SetTheme("Dark") WindUI:SetLanguage(Creator.Language) function WindUI:CreateWindow(Config) - local CreateWindow = require("./components/window/Init") - - if not RunService:IsStudio() and writefile then - if not isfolder("WindUI") then - makefolder("WindUI") - end - if Config.Folder then - makefolder(Config.Folder) - else - makefolder(Config.Title) - end - end - - Config.WindUI = WindUI - Config.Window = WindUI.Window - Config.Parent = WindUI.ScreenGui.Window - - if WindUI.Window then - warn("You cannot create more than one window") - return - end - - local CanLoadWindow = true - - local Theme = WindUI.Themes[Config.Theme or "Dark"] - - --WindUI.Theme = Theme - Creator.SetTheme(Theme) - - local hwid = gethwid or function() - return Players.LocalPlayer.UserId - end - - local Filename = hwid() - - if Config.KeySystem then - CanLoadWindow = false - - local function loadKeysystem() - KeySystem.new(Config, Filename, function(c) - CanLoadWindow = c - end) - end - - local keyPath = (Config.Folder or "Temp") .. "/" .. Filename .. ".key" - - if Config.KeySystem.KeyValidator then - if Config.KeySystem.SaveKey and isfile(keyPath) then - local savedKey = readfile(keyPath) - local isValid = Config.KeySystem.KeyValidator(savedKey) - - if isValid then - CanLoadWindow = true - else - loadKeysystem() - end - else - loadKeysystem() - end - elseif not Config.KeySystem.API then - if Config.KeySystem.SaveKey and isfile(keyPath) then - local savedKey = readfile(keyPath) - local isKey = (type(Config.KeySystem.Key) == "table") and table.find(Config.KeySystem.Key, savedKey) - or tostring(Config.KeySystem.Key) == tostring(savedKey) - - if isKey then - CanLoadWindow = true - else - loadKeysystem() - end - else - loadKeysystem() - end - else - if isfile(keyPath) then - local fileKey = readfile(keyPath) - local isSuccess = false - - for _, i in next, Config.KeySystem.API do - local serviceData = WindUI.Services[i.Type] - if serviceData then - local args = {} - for _, argName in next, serviceData.Args do - table.insert(args, i[argName]) - end - - local service = serviceData.New(table.unpack(args)) - local success = service.Verify(fileKey) - if success then - isSuccess = true - break - end - end - end - - CanLoadWindow = isSuccess - if not isSuccess then - loadKeysystem() - end - else - loadKeysystem() - end - end - - repeat - task.wait() - until CanLoadWindow - end - - local Window = CreateWindow(Config) - - WindUI.Transparent = Config.Transparent - WindUI.Window = Window - - if Config.Acrylic then - Acrylic.init() - end - - -- function Window:ToggleTransparency(Value) - -- WindUI.Transparent = Value - -- WindUI.Window.Transparent = Value - - -- Window.UIElements.Main.Background.BackgroundTransparency = Value and WindUI.TransparencyValue or 0 - -- Window.UIElements.Main.Background.ImageLabel.ImageTransparency = Value and WindUI.TransparencyValue or 0 - -- Window.UIElements.Main.Gradient.UIGradient.Transparency = NumberSequence.new{ - -- NumberSequenceKeypoint.new(0, 1), - -- NumberSequenceKeypoint.new(1, Value and 0.85 or 0.7), - -- } - -- end - - return Window + local CreateWindow = require("./components/window/Init") + if not RunService:IsStudio() and writefile then + if not isfolder("WindUI") then makefolder("WindUI") end + if Config.Folder then makefolder(Config.Folder) else makefolder(Config.Title) end + end + Config.WindUI = WindUI + Config.Window = WindUI.Window + Config.Parent = WindUI.ScreenGui.Window + if WindUI.Window then + warn("You cannot create more than one window") + return + end + local CanLoadWindow = true + local Theme = WindUI.Themes[Config.Theme or "Dark"] + --WindUI.Theme = Theme + Creator.SetTheme(Theme) + local hwid = gethwid or function() return Players.LocalPlayer.UserId end + local Filename = hwid() + if Config.KeySystem then + CanLoadWindow = false + local function loadKeysystem() + KeySystem.new(Config, Filename, function(c) CanLoadWindow = c end) + end + local keyPath = (Config.Folder or "Temp") .. "/" .. Filename .. ".key" + if Config.KeySystem.KeyValidator then + if Config.KeySystem.SaveKey and isfile(keyPath) then + local savedKey = readfile(keyPath) + local isValid = Config.KeySystem.KeyValidator(savedKey) + if isValid then CanLoadWindow = true else loadKeysystem() end + else loadKeysystem() end + elseif not Config.KeySystem.API then + if Config.KeySystem.SaveKey and isfile(keyPath) then + local savedKey = readfile(keyPath) + local isKey = (type(Config.KeySystem.Key) == "table") and table.find(Config.KeySystem.Key, savedKey) or tostring(Config.KeySystem.Key) == tostring(savedKey) + if isKey then CanLoadWindow = true else loadKeysystem() end + else loadKeysystem() end + else + if isfile(keyPath) then + local fileKey = readfile(keyPath) + local isSuccess = false + for _, i in next, Config.KeySystem.API do + local serviceData = WindUI.Services[i.Type] + if serviceData then + local args = {} + for _, argName in next, serviceData.Args do + table.insert(args, i[argName]) + end + local service = serviceData.New(table.unpack(args)) + local success = service.Verify(fileKey) + if success then isSuccess = true break end + end + end + CanLoadWindow = isSuccess + if not isSuccess then loadKeysystem() end + else loadKeysystem() end + end + repeat task.wait() until CanLoadWindow + end + local Window = CreateWindow(Config) + WindUI.Transparent = Config.Transparent + WindUI.Window = Window + if Config.Acrylic then Acrylic.init() end + -- function Window:ToggleTransparency(Value) + -- WindUI.Transparent = Value + -- WindUI.Window.Transparent = Value + -- Window.UIElements.Main.Background.BackgroundTransparency = Value and WindUI.TransparencyValue or 0 + -- Window.UIElements.Main.Background.ImageLabel.ImageTransparency = Value and WindUI.TransparencyValue or 0 + -- Window.UIElements.Main.Gradient.UIGradient.Transparency = NumberSequence.new{ + -- NumberSequenceKeypoint.new(0, 1), + -- NumberSequenceKeypoint.new(1, Value and 0.85 or 0.7), + -- } + -- end + return Window end return WindUI From fe28aefb118462a599dcb1cbb0bb224193208ad5 Mon Sep 17 00:00:00 2001 From: Sxmple Date: Thu, 13 Aug 2026 14:10:10 +0300 Subject: [PATCH 2/3] Implement metatable for dynamic UI element access Added metatable to Tab for dynamic element creation. --- src/components/window/Tab.lua | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/components/window/Tab.lua b/src/components/window/Tab.lua index 47593009..d02158f1 100644 --- a/src/components/window/Tab.lua +++ b/src/components/window/Tab.lua @@ -574,6 +574,26 @@ function TabModule.New(Config, UIScale) end) end) + setmetatable(Tab, { + __index = function(self, key) + local registeredWindUI = WindUI or (Window and Window.WindUI) + if not registeredWindUI then + pcall(function() + registeredWindUI = require("../../Init") + end) + end + + if registeredWindUI and registeredWindUI.RegisteredElements and registeredWindUI.RegisteredElements[key] then + local registeredElement = registeredWindUI.RegisteredElements[key] + return function(_, options) + return registeredElement.Create(registeredWindUI, self, options) + end + end + + return nil + end, + }) + return Tab end From a3d209a8f77f7dbf78c6291a6771ae8fc89136b1 Mon Sep 17 00:00:00 2001 From: Sxmple Date: Thu, 13 Aug 2026 14:21:57 +0300 Subject: [PATCH 3/3] Update build.yml --- .github/workflows/build.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d6a0bb01..0cf4d908 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,14 +8,19 @@ jobs: build: runs-on: ubuntu-latest + permissions: + contents: write + issues: write + pull-requests: write + steps: - name: Checkout uses: actions/checkout@v4 - name: Setup Node.js - uses: actions/setup-node@v5 + uses: actions/setup-node@v4 with: - node-version: 18 + node-version: 20 - name: Install dependencies run: npm install @@ -40,4 +45,4 @@ jobs: git config user.email "github-actions[bot]@users.noreply.github.com" git add dist/main.lua git commit -m "[AUTO] Upload built main.lua" || exit 0 - git push \ No newline at end of file + git push