local Players = game:GetService("Players") local CoreGui = game:GetService("CoreGui") local UserInputService = game:GetService("UserInputService") local RunService = game:GetService("RunService") local TweenService = game:GetService("TweenService") local player = Players.LocalPlayer local ROOT_NAME = "RBS_GUI_Studio" local function DestroyOld(container) pcall(function() local old = container:FindFirstChild(ROOT_NAME) if old then old:Destroy() end end) end DestroyOld(CoreGui) if player then local pg = player:FindFirstChildOfClass("PlayerGui") if pg then DestroyOld(pg) end end if gethui then pcall(function() DestroyOld(gethui()) end) end local ScreenGui = Instance.new("ScreenGui") ScreenGui.Name = ROOT_NAME ScreenGui.ResetOnSpawn = false ScreenGui.IgnoreGuiInset = true ScreenGui.DisplayOrder = 999999 ScreenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling local parented = false if gethui then parented = pcall(function() ScreenGui.Parent = gethui() end) and ScreenGui.Parent ~= nil end if not parented then parented = pcall(function() ScreenGui.Parent = CoreGui end) and ScreenGui.Parent ~= nil end if not parented then ScreenGui.Parent = player:WaitForChild("PlayerGui") end local Conns = {} local function Track(c) Conns[#Conns + 1] = c return c end ScreenGui.Destroying:Connect(function() for _, c in ipairs(Conns) do pcall(function() c:Disconnect() end) end end) local Theme = { Bg = Color3.fromRGB(16, 16, 20), Panel = Color3.fromRGB(24, 24, 29), Item = Color3.fromRGB(35, 35, 42), ItemHover = Color3.fromRGB(48, 48, 58), Stroke = Color3.fromRGB(62, 62, 74), Accent = Color3.fromRGB(0, 140, 255), AccentDark = Color3.fromRGB(0, 100, 185), Text = Color3.fromRGB(236, 236, 242), Sub = Color3.fromRGB(150, 150, 164), Danger = Color3.fromRGB(235, 70, 70), DangerDark = Color3.fromRGB(160, 45, 45), Success = Color3.fromRGB(60, 200, 120), } local function New(class, props, parent) local obj = Instance.new(class) for k, v in pairs(props or {}) do obj[k] = v end obj.Parent = parent return obj end local function Corner(obj, radius) return New("UICorner", { CornerRadius = UDim.new(0, radius) }, obj) end local function Stroke(obj, color, thickness) return New("UIStroke", { Color = color, Thickness = thickness, ApplyStrokeMode = Enum.ApplyStrokeMode.Border, }, obj) end local function Pad(obj, l, t, r, b) return New("UIPadding", { PaddingLeft = UDim.new(0, l), PaddingTop = UDim.new(0, t), PaddingRight = UDim.new(0, r), PaddingBottom = UDim.new(0, b), }, obj) end local function Tween(obj, props, t) TweenService:Create( obj, TweenInfo.new(t or 0.12, Enum.EasingStyle.Quad), props ):Play() end local function IsClick(input) return input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch end local function IsMove(input) return input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch end local function Button(props, parent, base, hover) base = base or Theme.Item hover = hover or Theme.ItemHover local b = New("TextButton", { BackgroundColor3 = base, AutoButtonColor = false, Text = "", TextColor3 = Theme.Text, TextSize = 13, Font = Enum.Font.GothamMedium, BorderSizePixel = 0, }, nil) for k, v in pairs(props or {}) do b[k] = v end b:SetAttribute("Base", base) b:SetAttribute("Hover", hover) b.Parent = parent Corner(b, 6) b.MouseEnter:Connect(function() Tween(b, { BackgroundColor3 = b:GetAttribute("Hover") }) end) b.MouseLeave:Connect(function() Tween(b, { BackgroundColor3 = b:GetAttribute("Base") }) end) return b end local function Dragify(handle, target) local dragging = false local startMouse local startPos handle.InputBegan:Connect(function(input) if IsClick(input) then dragging = true startMouse = input.Position startPos = target.Position end end) Track(UserInputService.InputChanged:Connect(function(input) if dragging and IsMove(input) then local d = input.Position - startMouse target.Position = UDim2.new( startPos.X.Scale, math.round(startPos.X.Offset + d.X), startPos.Y.Scale, math.round(startPos.Y.Offset + d.Y) ) end end)) Track(UserInputService.InputEnded:Connect(function(input) if IsClick(input) then dragging = false end end)) end local function Num(n) if n == math.floor(n) then return tostring(math.floor(n)) end local s = string.format("%.4f", n) s = s:gsub("0+$", "") s = s:gsub("%.$", "") return s end local function ColorStr(c) return string.format( "%d, %d, %d", math.round(c.R * 255), math.round(c.G * 255), math.round(c.B * 255) ) end local function FormatValue(v) local t = typeof(v) if t == "Color3" then return ColorStr(v) elseif t == "UDim2" then return string.format( "%s, %s, %s, %s", Num(v.X.Scale), Num(v.X.Offset), Num(v.Y.Scale), Num(v.Y.Offset) ) elseif t == "UDim" then return string.format( "%s, %s", Num(v.Scale), Num(v.Offset) ) elseif t == "Vector2" then return string.format( "%s, %s", Num(v.X), Num(v.Y) ) elseif t == "Vector3" then return string.format( "%s, %s, %s", Num(v.X), Num(v.Y), Num(v.Z) ) elseif t == "NumberRange" then return string.format( "%s, %s", Num(v.Min), Num(v.Max) ) elseif t == "Rect" then return string.format( "%s, %s, %s, %s", Num(v.Min.X), Num(v.Min.Y), Num(v.Max.X), Num(v.Max.Y) ) elseif t == "EnumItem" then return v.Name elseif t == "number" then return Num(v) elseif t == "ColorSequence" then local kp = v.Keypoints return ColorStr(kp[1].Value) .. " | " .. ColorStr(kp[#kp].Value) elseif t == "NumberSequence" then local kp = v.Keypoints return Num(kp[1].Value) .. ", " .. Num(kp[#kp].Value) end return tostring(v) end local function Nums(text) local r = {} for s in tostring(text):gmatch("%-?%d*%.?%d+") do local n = tonumber(s) if n then r[#r + 1] = n end end return r end local function ParseColor3(text) local hex = text:match("^%s*#(%x%x%x%x%x%x)%s*$") if hex then return Color3.fromRGB( tonumber(hex:sub(1, 2), 16), tonumber(hex:sub(3, 4), 16), tonumber(hex:sub(5, 6), 16) ) end local n = Nums(text) if #n == 3 then local r, g, b = n[1], n[2], n[3] if r > 1 or g > 1 or b > 1 then r, g, b = r / 255, g / 255, b / 255 end return Color3.new( math.clamp(r, 0, 1), math.clamp(g, 0, 1), math.clamp(b, 0, 1) ) end return nil end local function ParseBool(text) text = text:lower():gsub("%s+", "") if text == "true" or text == "1" or text == "yes" then return true end if text == "false" or text == "0" or text == "no" then return false end return nil end local function ParseValue(current, text) local t = typeof(current) local n = Nums(text) if t == "string" then return text elseif t == "number" then return tonumber(text) elseif t == "boolean" then return ParseBool(text) elseif t == "Color3" then return ParseColor3(text) elseif t == "UDim2" then if #n == 4 then return UDim2.new(n[1], n[2], n[3], n[4]) elseif #n == 2 then return UDim2.fromOffset(n[1], n[2]) end elseif t == "UDim" then if #n == 2 then return UDim.new(n[1], n[2]) end elseif t == "Vector2" then if #n == 2 then return Vector2.new(n[1], n[2]) end elseif t == "Vector3" then if #n == 3 then return Vector3.new(n[1], n[2], n[3]) end elseif t == "NumberRange" then if #n == 2 then return NumberRange.new(n[1], n[2]) end elseif t == "Rect" then if #n == 4 then return Rect.new(n[1], n[2], n[3], n[4]) end elseif t == "NumberSequence" then if #n == 1 then return NumberSequence.new(n[1]) elseif #n == 2 then return NumberSequence.new(n[1], n[2]) end elseif t == "ColorSequence" then local parts = {} for part in (text .. "|"):gmatch("([^|]*)|") do if part:match("%S") then parts[#parts + 1] = part end end local c1 = parts[1] and ParseColor3(parts[1]) local c2 = parts[2] and ParseColor3(parts[2]) if c1 and c2 then return ColorSequence.new(c1, c2) elseif c1 then return ColorSequence.new(c1) end elseif t == "EnumItem" then local low = text:lower():gsub("%s+", "") for _, item in ipairs(current.EnumType:GetEnumItems()) do if item.Name:lower() == low or tostring(item):lower() == low or tostring(item.Value) == low then return item end end end return nil end local function LuaValue(v) local t = typeof(v) if t == "string" then return string.format("%q", v) elseif t == "number" then return string.format("%.10g", v) elseif t == "boolean" then return tostring(v) elseif t == "Color3" then return string.format( "Color3.fromRGB(%d, %d, %d)", math.round(v.R * 255), math.round(v.G * 255), math.round(v.B * 255) ) elseif t == "UDim2" then return string.format( "UDim2.new(%s, %s, %s, %s)", Num(v.X.Scale), Num(v.X.Offset), Num(v.Y.Scale), Num(v.Y.Offset) ) elseif t == "UDim" then return string.format( "UDim.new(%s, %s)", Num(v.Scale), Num(v.Offset) ) elseif t == "Vector2" then return string.format( "Vector2.new(%s, %s)", Num(v.X), Num(v.Y) ) elseif t == "Vector3" then return string.format( "Vector3.new(%s, %s, %s)", Num(v.X), Num(v.Y), Num(v.Z) ) elseif t == "NumberRange" then return string.format( "NumberRange.new(%s, %s)", Num(v.Min), Num(v.Max) ) elseif t == "Rect" then return string.format( "Rect.new(%s, %s, %s, %s)", Num(v.Min.X), Num(v.Min.Y), Num(v.Max.X), Num(v.Max.Y) ) elseif t == "EnumItem" then return tostring(v) elseif t == "ColorSequence" then local parts = {} for _, k in ipairs(v.Keypoints) do parts[#parts + 1] = string.format( "ColorSequenceKeypoint.new(%s, %s)", Num(k.Time), string.format( "Color3.fromRGB(%d, %d, %d)", math.round(k.Value.R * 255), math.round(k.Value.G * 255), math.round(k.Value.B * 255) ) ) end return "ColorSequence.new({" .. table.concat(parts, ", ") .. "})" elseif t == "NumberSequence" then local parts = {} for _, k in ipairs(v.Keypoints) do parts[#parts + 1] = string.format( "NumberSequenceKeypoint.new(%s, %s, %s)", Num(k.Time), Num(k.Value), Num(k.Envelope) ) end return "NumberSequence.new({" .. table.concat(parts, ", ") .. "})" end return nil end local Schema = { { "Object", { "Instance" }, { "Name" } }, { "Layout", { "GuiObject" }, { "AnchorPoint", "Position", "Size", "Rotation", "SizeConstraint", "AutomaticSize", "LayoutOrder", "ZIndex", "Visible", "ClipsDescendants", "Active", "Selectable", } }, { "Appearance", { "GuiObject" }, { "BackgroundColor3", "BackgroundTransparency", "BorderColor3", "BorderMode", "BorderSizePixel", } }, { "Canvas Group", { "CanvasGroup" }, { "GroupColor3", "GroupTransparency", } }, { "Button", { "GuiButton" }, { "AutoButtonColor", "Modal", "Style", } }, { "Text", { "TextLabel", "TextButton", "TextBox" }, { "Text", "TextColor3", "TextTransparency", "TextSize", "Font", "TextScaled", "TextWrapped", "RichText", "TextXAlignment", "TextYAlignment", "LineHeight", "MaxVisibleGraphemes", "TextStrokeColor3", "TextStrokeTransparency", "TextTruncate", "TextDirection", } }, { "TextBox", { "TextBox" }, { "PlaceholderText", "PlaceholderColor3", "ClearTextOnFocus", "MultiLine", "TextEditable", "ShowNativeInput", } }, { "Image", { "ImageLabel", "ImageButton" }, { "Image", "ImageColor3", "ImageTransparency", "ScaleType", "ResampleMode", "ImageRectOffset", "ImageRectSize", "SliceCenter", "SliceScale", "TileSize", } }, { "Image Button", { "ImageButton" }, { "HoverImage", "PressedImage", } }, { "Scrolling", { "ScrollingFrame" }, { "CanvasSize", "CanvasPosition", "AutomaticCanvasSize", "ScrollingEnabled", "ScrollingDirection", "ScrollBarThickness", "ScrollBarImageColor3", "ScrollBarImageTransparency", "ElasticBehavior", "HorizontalScrollBarInset", "VerticalScrollBarInset", "VerticalScrollBarPosition", } }, { "UICorner", { "UICorner" }, { "CornerRadius", } }, { "UIStroke", { "UIStroke" }, { "Enabled", "Color", "Thickness", "Transparency", "ApplyStrokeMode", "LineJoinMode", } }, { "UIGradient", { "UIGradient" }, { "Enabled", "Color", "Transparency", "Rotation", "Offset", } }, { "UIListLayout", { "UIListLayout" }, { "FillDirection", "HorizontalAlignment", "VerticalAlignment", "SortOrder", "Padding", "Wraps", "HorizontalFlex", "VerticalFlex", "ItemLineAlignment", } }, { "UIGridLayout", { "UIGridLayout" }, { "CellSize", "CellPadding", "FillDirection", "FillDirectionMaxCells", "StartCorner", "HorizontalAlignment", "VerticalAlignment", "SortOrder", } }, { "UIPadding", { "UIPadding" }, { "PaddingTop", "PaddingBottom", "PaddingLeft", "PaddingRight", } }, { "UIScale", { "UIScale" }, { "Scale", } }, { "UIAspectRatioConstraint", { "UIAspectRatioConstraint" }, { "AspectRatio", "AspectType", "DominantAxis", } }, { "UISizeConstraint", { "UISizeConstraint" }, { "MinSize", "MaxSize", } }, } local function Matches(obj, classes) for _, c in ipairs(classes) do if obj:IsA(c) then return true end end return false end local function IsGuiObject(obj) return obj ~= nil and obj:IsA("GuiObject") end local function Listed(obj) return obj:IsA("GuiObject") or obj:IsA("UIComponent") end local BLUE = Color3.fromRGB(0, 120, 215) local GREEN = Color3.fromRGB(45, 160, 100) local ORANGE = Color3.fromRGB(220, 130, 40) local TEAL = Color3.fromRGB(30, 170, 175) local PURPLE = Color3.fromRGB(140, 80, 220) local MetaTable = { Frame = { "Fr", BLUE }, CanvasGroup = { "Cg", BLUE }, ScrollingFrame = { "Sc", TEAL }, TextLabel = { "Tx", GREEN }, TextButton = { "Bt", GREEN }, TextBox = { "Tb", GREEN }, ImageLabel = { "Im", ORANGE }, ImageButton = { "Ib", ORANGE }, UICorner = { "Co", PURPLE }, UIStroke = { "St", PURPLE }, UIListLayout = { "Li", PURPLE }, UIGridLayout = { "Gr", PURPLE }, UIGradient = { "Gd", PURPLE }, UIPadding = { "Pd", PURPLE }, UIScale = { "Sl", PURPLE }, UIAspectRatioConstraint = { "Ar", PURPLE }, UISizeConstraint = { "Sz", PURPLE }, } local function MetaByClass(className) local m = MetaTable[className] if m then return m[1], m[2] end return "UI", PURPLE end local UI = {} local Selected local GuiTarget local SetSelected local BuildProperties local RefreshProperties local RefreshExplorer local UpdateSelection local CloseMenus local OpenPalette local Notify local UpdateToolbar local PropRefreshers = {} local Drag = { mode = nil } local function Viewport() local s = ScreenGui.AbsoluteSize if s.X == 0 or s.Y == 0 then local cam = workspace.CurrentCamera if cam then return cam.ViewportSize end return Vector2.new(1280, 720) end return s end local Editor = New("Frame", { Name = "Editor", BackgroundColor3 = Color3.fromRGB(10, 10, 13), BackgroundTransparency = 0.3, BorderSizePixel = 0, Size = UDim2.fromScale(1, 1), Active = true, ZIndex = 1, }, ScreenGui) local Canvas = New("Frame", { Name = "Canvas", AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.fromOffset(700, 450), BackgroundColor3 = Color3.fromRGB(30, 30, 37), BorderSizePixel = 0, ClipsDescendants = true, ZIndex = 2, }, Editor) local CanvasBorder = New("Frame", { Name = "CanvasBorder", AnchorPoint = Vector2.new(0.5, 0.5), Position = UDim2.fromScale(0.5, 0.5), Size = UDim2.fromOffset(700, 450), BackgroundTransparency = 1, BorderSizePixel = 0, ZIndex = 3, }, Editor) Stroke(CanvasBorder, Theme.Stroke, 1) local Selection = New("Frame", { Name = "Selection", BackgroundTransparency = 1, BorderSizePixel = 0, Visible = false, ZIndex = 50, }, Editor) Stroke(Selection, Theme.Accent, 2) local Handle = New("Frame", { Name = "ResizeHandle", Size = UDim2.fromOffset(16, 16), AnchorPoint = Vector2.new(0.5, 0.5), BackgroundColor3 = Theme.Accent, BorderSizePixel = 0, Visible = false, Active = true, ZIndex = 51, }, Editor) Corner(Handle, 8) Stroke(Handle, Color3.new(1, 1, 1), 2) function UpdateSelection() local g = GuiTarget if not g or not g.Parent or not g:IsDescendantOf(Canvas) then Selection.Visible = false Handle.Visible = false return end local pos = g.AbsolutePosition local size = g.AbsoluteSize local origin = Editor.AbsolutePosition Selection.Position = UDim2.fromOffset( pos.X - origin.X, pos.Y - origin.Y ) Selection.Size = UDim2.fromOffset( size.X, size.Y ) Handle.Position = UDim2.fromOffset( pos.X - origin.X + size.X, pos.Y - origin.Y + size.Y ) Selection.Visible = true Handle.Visible = true end local Pending local function Candidate(obj, input) local depth = 0 if obj then local p = obj while p and p ~= Canvas do depth += 1 p = p.Parent end end if Pending then if depth > Pending.depth then Pending.obj = obj Pending.depth = depth end return end local mine = { obj = obj, depth = depth } Pending = mine task.defer(function() if Pending == mine then Pending = nil end CloseMenus() if mine.obj and mine.obj.Parent then SetSelected(mine.obj) Drag.mode = "move" Drag.obj = mine.obj Drag.start = input.Position Drag.origin = mine.obj.Position Drag.moved = false else SetSelected(nil) end end) end local Hooked = setmetatable({}, { __mode = "k" }) local function Hook(obj) if Hooked[obj] or not IsGuiObject(obj) then return end Hooked[obj] = true obj.InputBegan:Connect(function(input) if IsClick(input) then Candidate(obj, input) end end) if obj:IsA("TextBox") then obj.Focused:Connect(function() obj:ReleaseFocus() end) end for _, child in ipairs(obj:GetChildren()) do Hook(child) end end Canvas.InputBegan:Connect(function(input) if IsClick(input) then Candidate(nil, input) end end) local BG = Color3.fromRGB(45, 45, 52) local ObjectDefaults = { Frame = { Size = UDim2.fromOffset(180, 100), BackgroundColor3 = BG }, CanvasGroup = { Size = UDim2.fromOffset(180, 100), BackgroundColor3 = BG }, TextLabel = { Size = UDim2.fromOffset(180, 40), BackgroundColor3 = BG, Text = "TextLabel", TextColor3 = Color3.new(1, 1, 1), Font = Enum.Font.GothamMedium, TextSize = 14, }, TextButton = { Size = UDim2.fromOffset(180, 40), BackgroundColor3 = BG, Text = "TextButton", TextColor3 = Color3.new(1, 1, 1), Font = Enum.Font.GothamMedium, TextSize = 14, }, TextBox = { Size = UDim2.fromOffset(180, 40), BackgroundColor3 = BG, Text = "TextBox", PlaceholderText = "Type here...", TextColor3 = Color3.new(1, 1, 1), Font = Enum.Font.GothamMedium, TextSize = 14, ClearTextOnFocus = false, }, ImageLabel = { Size = UDim2.fromOffset(100, 100), BackgroundColor3 = BG }, ImageButton = { Size = UDim2.fromOffset(100, 100), BackgroundColor3 = BG }, ScrollingFrame = { Size = UDim2.fromOffset(200, 150), BackgroundColor3 = BG, CanvasSize = UDim2.fromOffset(0, 400), ScrollBarThickness = 4, }, } local Addables = { "Frame", "CanvasGroup", "ScrollingFrame", "TextLabel", "TextButton", "TextBox", "ImageLabel", "ImageButton" } local ModifierInit = { UICorner = function(o) o.CornerRadius = UDim.new(0, 8) end, UIStroke = function(o) o.ApplyStrokeMode = Enum.ApplyStrokeMode.Border o.Color = Color3.fromRGB(0, 140, 255) o.Thickness = 2 end, UIListLayout = function(o) o.Padding = UDim.new(0, 6) o.SortOrder = Enum.SortOrder.LayoutOrder end, UIGridLayout = function(o) o.CellSize = UDim2.fromOffset(80, 80) o.CellPadding = UDim2.fromOffset(6, 6) o.SortOrder = Enum.SortOrder.LayoutOrder end, UIGradient = function(o) o.Color = ColorSequence.new( Color3.fromRGB(0, 140, 255), Color3.fromRGB(150, 80, 235) ) o.Rotation = 45 end, UIPadding = function(o) o.PaddingTop = UDim.new(0, 8) o.PaddingBottom = UDim.new(0, 8) o.PaddingLeft = UDim.new(0, 8) o.PaddingRight = UDim.new(0, 8) end, UIScale = function(o) o.Scale = 1 end, UIAspectRatioConstraint = function(o) o.AspectRatio = 1 end, UISizeConstraint = function(o) o.MinSize = Vector2.new(20, 20) o.MaxSize = Vector2.new(1000, 1000) end, } local ModifierList = { "UICorner", "UIStroke", "UIGradient", "UIListLayout", "UIGridLayout", "UIPadding", "UIScale", "UIAspectRatioConstraint", "UISizeConstraint", } local function CreateObject(className, parent) local obj = Instance.new(className) for k, v in pairs(ObjectDefaults[className] or {}) do obj[k] = v end local n = #Canvas:GetChildren() % 6 obj.Name = className obj.Position = UDim2.fromOffset( 24 + n * 20, 24 + n * 20 ) obj.BorderSizePixel = 0 obj.Parent = parent or Canvas Hook(obj) return obj end local function AddModifierTo(target, className) local obj = Instance.new(className) local init = ModifierInit[className] if init then init(obj) end obj.Parent = target return obj end local function AddModifier(className) if not GuiTarget then Notify("Select an object first", Theme.Danger) return end local existing = GuiTarget:FindFirstChildOfClass(className) if existing then SetSelected(existing) return end local m = AddModifierTo(GuiTarget, className) SetSelected(m) end local function ResolveParent() local base = GuiTarget if base then if base:IsA("Frame") or base:IsA("ScrollingFrame") or base:IsA("CanvasGroup") then return base end if base.Parent and IsGuiObject(base.Parent) then return base.Parent end end return Canvas end local function DeleteSelected() if not Selected then return end local obj = Selected local nextSel = nil if not IsGuiObject(obj) then nextSel = GuiTarget elseif obj.Parent ~= Canvas and IsGuiObject(obj.Parent) then nextSel = obj.Parent end obj:Destroy() SetSelected(nextSel) end local function DuplicateSelected() local src = GuiTarget if not src or not src.Parent then return end local clone = src:Clone() local p = src.Position clone.Position = UDim2.new( p.X.Scale, p.X.Offset + 14, p.Y.Scale, p.Y.Offset + 14 ) clone.Parent = src.Parent Hook(clone) SetSelected(clone) end local function MakePanel(title, size, position, z) local frame = New("Frame", { Name = title, Size = size, Position = position, BackgroundColor3 = Theme.Panel, BorderSizePixel = 0, Active = true, Visible = false, ZIndex = z, }, ScreenGui) Corner(frame, 10) Stroke(frame, Theme.Stroke, 1) local header = New("Frame", { Size = UDim2.new(1, 0, 0, 36), BackgroundColor3 = Theme.Item, BorderSizePixel = 0, }, frame) Corner(header, 10) New("Frame", { Position = UDim2.new(0, 0, 1, -10), Size = UDim2.new(1, 0, 0, 10), BackgroundColor3 = Theme.Item, BorderSizePixel = 0, }, header) local titleLabel = New("TextLabel", { Position = UDim2.fromOffset(12, 0), Size = UDim2.new(1, -50, 1, 0), BackgroundTransparency = 1, Text = title, TextColor3 = Theme.Text, TextSize = 14, Font = Enum.Font.GothamBold, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, }, header) local close = Button({ Position = UDim2.new(1, -32, 0, 5), Size = UDim2.fromOffset(26, 26), Text = "×", TextSize = 18, }, header, Theme.Item, Theme.DangerDark) close.MouseButton1Click:Connect(function() frame.Visible = false end) local body = New("ScrollingFrame", { Position = UDim2.fromOffset(6, 42), Size = UDim2.new(1, -12, 1, -48), BackgroundTransparency = 1, BorderSizePixel = 0, ScrollBarThickness = 3, ScrollBarImageColor3 = Theme.Stroke, CanvasSize = UDim2.new(), AutomaticCanvasSize = Enum.AutomaticSize.Y, }, frame) New("UIListLayout", { Padding = UDim.new(0, 4), SortOrder = Enum.SortOrder.LayoutOrder, }, body) Dragify(header, frame) return frame, body, titleLabel end UI.Explorer, UI.ExplorerBody = MakePanel( "Explorer", UDim2.new(0, 240, 0.55, 0), UDim2.fromOffset(10, 62), 11 ) UI.Props, UI.PropBody, UI.PropTitle = MakePanel( "Properties", UDim2.new(0, 290, 0.8, 0), UDim2.new(1, -300, 0, 62), 11 ) UI.Props.Visible = true UI.Code, UI.CodeBody = MakePanel( "Generated Luau", UDim2.fromOffset(480, 380), UDim2.new(0.5, -240, 0.5, -190), 30 ) local ExplorerQueued = false function RefreshExplorer() if ExplorerQueued then return end ExplorerQueued = true task.defer(function() ExplorerQueued = false if not UI.Explorer.Visible then return end for _, c in ipairs(UI.ExplorerBody:GetChildren()) do if c:IsA("GuiObject") then c:Destroy() end end local order = 0 local function add(obj, depth) order += 1 local sel = obj == Selected local row = Button({ Size = UDim2.new(1, -6, 0, 28), LayoutOrder = order, }, UI.ExplorerBody, sel and Theme.AccentDark or Theme.Panel, sel and Theme.Accent or Theme.ItemHover ) local tag, col = MetaByClass(obj.ClassName) local badge = New("TextLabel", { Position = UDim2.fromOffset( 6 + depth * 14, 5 ), Size = UDim2.fromOffset(22, 18), BackgroundColor3 = col, BorderSizePixel = 0, Text = tag, TextColor3 = Color3.new(1, 1, 1), TextSize = 10, Font = Enum.Font.GothamBold, }, row) Corner(badge, 4) New("TextLabel", { Position = UDim2.fromOffset( 34 + depth * 14, 0 ), Size = UDim2.new( 1, -40 - depth * 14, 1, 0 ), BackgroundTransparency = 1, Text = obj.Name, TextColor3 = Theme.Text, TextSize = 12, Font = Enum.Font.Gotham, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, }, row) row.MouseButton1Click:Connect(function() if obj.Parent then SetSelected(obj) end end) for _, child in ipairs(obj:GetChildren()) do if Listed(child) then add(child, depth + 1) end end end for _, child in ipairs(Canvas:GetChildren()) do if Listed(child) then add(child, 0) end end if order == 0 then New("TextLabel", { Size = UDim2.new(1, -6, 0, 30), BackgroundTransparency = 1, Text = "Canvas is empty", TextColor3 = Theme.Sub, TextSize = 12, Font = Enum.Font.Gotham, }, UI.ExplorerBody) end end) end Canvas.DescendantAdded:Connect(RefreshExplorer) Canvas.DescendantRemoving:Connect(RefreshExplorer) local PaletteCallback do local colors = {} local raw = { { 0, 0, 0 }, { 40, 40, 45 }, { 80, 80, 90 }, { 120, 120, 130 }, { 160, 160, 170 }, { 200, 200, 208 }, { 235, 235, 240 }, { 255, 255, 255 }, { 235, 70, 70 }, { 255, 145, 50 }, { 255, 210, 60 }, { 150, 220, 60 }, { 60, 200, 120 }, { 30, 200, 200 }, { 0, 140, 255 }, { 90, 90, 235 }, { 150, 80, 235 }, { 235, 80, 180 }, { 255, 110, 130 }, { 140, 90, 55 }, { 20, 40, 90 }, { 20, 90, 50 }, { 100, 25, 35 }, { 90, 45, 110 }, { 255, 180, 180 }, { 255, 215, 170 }, { 255, 240, 170 }, { 200, 240, 170 }, { 170, 235, 200 }, { 170, 230, 240 }, { 170, 200, 255 }, { 210, 185, 255 }, } for _, c in ipairs(raw) do colors[#colors + 1] = Color3.fromRGB( c[1], c[2], c[3] ) end local frame = New("Frame", { Name = "Palette", Size = UDim2.fromOffset(236, 164), BackgroundColor3 = Theme.Panel, BorderSizePixel = 0, Active = true, Visible = false, ZIndex = 25, }, ScreenGui) Corner(frame, 10) Stroke(frame, Theme.Stroke, 1) New("TextLabel", { Size = UDim2.new(1, 0, 0, 28), BackgroundTransparency = 1, Text = "Colors", TextColor3 = Theme.Text, TextSize = 13, Font = Enum.Font.GothamBold, }, frame) local grid = New("Frame", { Position = UDim2.fromOffset(8, 32), Size = UDim2.new(1, -16, 1, -40), BackgroundTransparency = 1, }, frame) New("UIGridLayout", { CellSize = UDim2.fromOffset(24, 24), CellPadding = UDim2.fromOffset(4, 4), SortOrder = Enum.SortOrder.LayoutOrder, }, grid) for i, c in ipairs(colors) do local b = New("TextButton", { BackgroundColor3 = c, Text = "", AutoButtonColor = false, BorderSizePixel = 0, LayoutOrder = i, }, grid) Corner(b, 6) Stroke(b, Theme.Stroke, 1) b.MouseButton1Click:Connect(function() if PaletteCallback then PaletteCallback(c) end frame.Visible = false end) end UI.Palette = frame end function OpenPalette(callback, anchor) PaletteCallback = callback local vp = Viewport() local ax = anchor.AbsolutePosition.X local ay = anchor.AbsolutePosition.Y local x = math.clamp( ax - 246, 6, math.max(6, vp.X - 242) ) local y = math.clamp( ay - 20, 58, math.max(58, vp.Y - 170) ) UI.Palette.Position = UDim2.fromOffset(x, y) UI.Palette.Visible = true end local function TextInput(parent, pos, size) local box = New("TextBox", { Position = pos, Size = size, BackgroundColor3 = Theme.Item, TextColor3 = Theme.Text, PlaceholderColor3 = Theme.Sub, TextSize = 11, Font = Enum.Font.Gotham, ClearTextOnFocus = false, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, BorderSizePixel = 0, Text = "", }, parent) Corner(box, 5) local st = Stroke(box, Theme.Stroke, 1) Pad(box, 6, 0, 4, 0) box.Focused:Connect(function() Tween(st, { Color = Theme.Accent }) end) box.FocusLost:Connect(function() Tween(st, { Color = Theme.Stroke }) end) return box end local function Swatch(parent, pos) local sw = New("TextButton", { Position = pos, Size = UDim2.fromOffset(24, 22), BackgroundColor3 = Color3.new(1, 1, 1), Text = "", AutoButtonColor = false, BorderSizePixel = 0, }, parent) Corner(sw, 5) Stroke(sw, Theme.Stroke, 1) return sw end local function AddRow(target, name, order) local ok, value = pcall(function() return target[name] end) if not ok or value == nil then return end local t = typeof(value) local row = New("Frame", { Size = UDim2.new(1, -6, 0, 30), BackgroundTransparency = 1, LayoutOrder = order, }, UI.PropBody) New("TextLabel", { Size = UDim2.new(0.38, -4, 1, 0), BackgroundTransparency = 1, Text = name, TextColor3 = Theme.Sub, TextSize = 11, Font = Enum.Font.Gotham, TextXAlignment = Enum.TextXAlignment.Left, TextTruncate = Enum.TextTruncate.AtEnd, }, row) local holder = New("Frame", { Position = UDim2.fromScale(0.38, 0), Size = UDim2.fromScale(0.62, 1), BackgroundTransparency = 1, }, row) local function read() local ok2, v = pcall(function() return target[name] end) if ok2 then return v end return nil end local function write(v) return pcall(function() target[name] = v end) end local function after() if name == "Name" then RefreshExplorer() end RefreshProperties() end if t == "boolean" then local btn = Button({ Position = UDim2.fromOffset(0, 2), Size = UDim2.new(1, 0, 1, -4), TextSize = 11, }, holder) btn.MouseButton1Click:Connect(function() write(not read()) after() end) table.insert(PropRefreshers, function() local v = read() local base = v and Theme.AccentDark or Theme.Item btn.Text = tostring(v) btn:SetAttribute("Base", base) btn:SetAttribute( "Hover", v and Theme.Accent or Theme.ItemHover ) btn.BackgroundColor3 = base end) elseif t == "EnumItem" then local items = value.EnumType:GetEnumItems() local function step(dir) local cur = read() local idx = table.find(items, cur) or 1 idx = ((idx - 1 + dir) % #items) + 1 write(items[idx]) after() end local prev = Button({ Position = UDim2.fromOffset(0, 2), Size = UDim2.fromOffset(22, 26), Text = "‹", TextSize = 16, }, holder) local mid = Button({ Position = UDim2.new(0, 24, 0, 2), Size = UDim2.new(1, -48, 1, -4), TextSize = 11, }, holder) local nxt = Button({ Position = UDim2.new(1, -22, 0, 2), Size = UDim2.fromOffset(22, 26), Text = "›", TextSize = 16, }, holder) prev.MouseButton1Click:Connect(function() step(-1) end) nxt.MouseButton1Click:Connect(function() step(1) end) mid.MouseButton1Click:Connect(function() step(1) end) table.insert(PropRefreshers, function() local v = read() if v then mid.Text = v.Name end end) elseif t == "Color3" then local sw = Swatch( holder, UDim2.fromOffset(0, 4) ) local box = TextInput( holder, UDim2.fromOffset(30, 2), UDim2.new(1, -30, 1, -4) ) local shown = "" sw.MouseButton1Click:Connect(function() OpenPalette(function(c) write(c) after() end, sw) end) box.FocusLost:Connect(function() if box.Text == shown then return end local nv = ParseValue(read(), box.Text) if nv ~= nil and write(nv) then after() else box.Text = shown end end) table.insert(PropRefreshers, function() local v = read() sw.BackgroundColor3 = v if not box:IsFocused() then shown = FormatValue(v) box.Text = shown end end) elseif t == "ColorSequence" then local sw1 = Swatch( holder, UDim2.fromOffset(0, 4) ) local sw2 = Swatch( holder, UDim2.fromOffset(28, 4) ) local box = TextInput( holder, UDim2.fromOffset(56, 2), UDim2.new(1, -56, 1, -4) ) local shown = "" local function setStop(index, c) local cur = read() local kp = cur.Keypoints local c1 = kp[1].Value local c2 = kp[#kp].Value if index == 1 then c1 = c else c2 = c end write(ColorSequence.new(c1, c2)) after() end sw1.MouseButton1Click:Connect(function() OpenPalette(function(c) setStop(1, c) end, sw1) end) sw2.MouseButton1Click:Connect(function() OpenPalette(function(c) setStop(2, c) end, sw2) end) box.FocusLost:Connect(function() if box.Text == shown then return end local nv = ParseValue(read(), box.Text) if nv ~= nil and write(nv) then after() else box.Text = shown end end) table.insert(PropRefreshers, function() local v = read() local kp = v.Keypoints sw1.BackgroundColor3 = kp[1].Value sw2.BackgroundColor3 = kp[#kp].Value if not box:IsFocused() then shown = FormatValue(v) box.Text = shown end end) else local box = TextInput( holder, UDim2.fromOffset(0, 2), UDim2.new(1, 0, 1, -4) ) local shown = "" box.FocusLost:Connect(function() if box.Text == shown then return end local nv = ParseValue(read(), box.Text) if nv ~= nil and write(nv) then after() else box.Text = shown end end) table.insert(PropRefreshers, function() if not box:IsFocused() then shown = FormatValue(read()) box.Text = shown end end) end end function RefreshProperties() for _, fn in ipairs(PropRefreshers) do pcall(fn) end end function BuildProperties() for _, c in ipairs(UI.PropBody:GetChildren()) do if c:IsA("GuiObject") then c:Destroy() end end table.clear(PropRefreshers) if not Selected or not Selected.Parent then UI.PropTitle.Text = "Properties" New("TextLabel", { Size = UDim2.new(1, -6, 0, 40), BackgroundTransparency = 1, Text = "Nothing selected", TextColor3 = Theme.Sub, TextSize = 12, Font = Enum.Font.Gotham, }, UI.PropBody) return end UI.PropTitle.Text = "Properties · " .. Selected.ClassName local order = 0 for _, sec in ipairs(Schema) do if Matches(Selected, sec[2]) then order += 1 New("TextLabel", { Size = UDim2.new(1, -6, 0, 22), BackgroundTransparency = 1, Text = string.upper(sec[1]), TextColor3 = Theme.Accent, TextSize = 10, Font = Enum.Font.GothamBold, TextXAlignment = Enum.TextXAlignment.Left, LayoutOrder = order, }, UI.PropBody) for _, name in ipairs(sec[3]) do order += 1 AddRow(Selected, name, order) end end end RefreshProperties() end function UpdateToolbar() local has = Selected ~= nil for _, b in ipairs({ UI.BtnStyle, UI.BtnDup, UI.BtnDel, UI.BtnProps }) do if b then b.Visible = has end end end function SetSelected(obj) Selected = obj if obj and obj:IsA("GuiObject") then GuiTarget = obj elseif obj and obj.Parent and obj.Parent:IsA("GuiObject") then GuiTarget = obj.Parent else GuiTarget = nil end BuildProperties() RefreshExplorer() UpdateSelection() UpdateToolbar() end local function MakePopup(title, classes, onPick) local frame = New("Frame", { Name = title, Size = UDim2.fromOffset( 210, 36 + #classes * 32 + 6 ), BackgroundColor3 = Theme.Panel, BorderSizePixel = 0, Active = true, Visible = false, ZIndex = 20, }, ScreenGui) Corner(frame, 10) Stroke(frame, Theme.Stroke, 1) New("TextLabel", { Size = UDim2.new(1, 0, 0, 32), BackgroundTransparency = 1, Text = title, TextColor3 = Theme.Text, TextSize = 14, Font = Enum.Font.GothamBold, }, frame) local list = New("Frame", { Position = UDim2.fromOffset(6, 34), Size = UDim2.new(1, -12, 1, -40), BackgroundTransparency = 1, }, frame) New("UIListLayout", { Padding = UDim.new(0, 4), SortOrder = Enum.SortOrder.LayoutOrder, }, list) for i, className in ipairs(classes) do local btn = Button({ Size = UDim2.new(1, 0, 0, 28), LayoutOrder = i, }, list) local tag, col = MetaByClass(className) local badge = New("TextLabel", { Position = UDim2.fromOffset(6, 5), Size = UDim2.fromOffset(22, 18), BackgroundColor3 = col, BorderSizePixel = 0, Text = tag, TextColor3 = Color3.new(1, 1, 1), TextSize = 10, Font = Enum.Font.GothamBold, }, btn) Corner(badge, 4) New("TextLabel", { Position = UDim2.fromOffset(36, 0), Size = UDim2.new(1, -42, 1, 0), BackgroundTransparency = 1, Text = className, TextColor3 = Theme.Text, TextSize = 12, Font = Enum.Font.GothamMedium, TextXAlignment = Enum.TextXAlignment.Left, }, btn) btn.MouseButton1Click:Connect(function() frame.Visible = false onPick(className) end) end return frame end UI.AddMenu = MakePopup( "Add Object", Addables, function(className) local obj = CreateObject( className, ResolveParent() ) SetSelected(obj) end ) UI.StyleMenu = MakePopup( "Add Style", ModifierList, AddModifier ) function CloseMenus() UI.AddMenu.Visible = false UI.StyleMenu.Visible = false UI.Palette.Visible = false end local function OpenPopup(popup, anchor) local was = popup.Visible CloseMenus() if was then return end local vp = Viewport() local x = math.clamp( anchor.AbsolutePosition.X, 6, math.max( 6, vp.X - popup.AbsoluteSize.X - 6 ) ) popup.Position = UDim2.fromOffset(x, 60) popup.Visible = true end function Notify(text, color) local f = New("Frame", { AnchorPoint = Vector2.new(0.5, 1), Position = UDim2.new(0.5, 0, 1, -24), Size = UDim2.fromOffset(0, 38), AutomaticSize = Enum.AutomaticSize.X, BackgroundColor3 = Theme.Panel, BorderSizePixel = 0, ZIndex = 40, }, ScreenGui) Corner(f, 8) Stroke(f, color or Theme.Accent, 1) Pad(f, 16, 0, 16, 0) New("TextLabel", { Size = UDim2.fromOffset(0, 38), AutomaticSize = Enum.AutomaticSize.X, BackgroundTransparency = 1, Text = text, TextColor3 = Theme.Text, TextSize = 13, Font = Enum.Font.GothamMedium, }, f) task.delay(2.2, function() if f.Parent then f:Destroy() end end) end local DefaultCache = {} local function GetDefault(className) if DefaultCache[className] == nil then local ok, inst = pcall( Instance.new, className ) DefaultCache[className] = ok and inst or false end return DefaultCache[className] end local function SafeName(str) local s = tostring(str):gsub( "[^%w_]", "" ) if s == "" then s = "Object" end return s end local function Generate( obj, depth, parentVar, lines, state ) state.n += 1 local var = SafeName(obj.Name) .. "_" .. state.n local pad = string.rep("\t", depth) local inner = pad .. "\t" local default = GetDefault(obj.ClassName) table.insert( lines, pad .. "do" ) table.insert( lines, inner .. "local " .. var .. " = Instance.new(" .. string.format("%q", obj.ClassName) .. ")" ) for _, sec in ipairs(Schema) do if Matches(obj, sec[2]) then for _, name in ipairs(sec[3]) do local ok, v = pcall(function() return obj[name] end) if ok and v ~= nil then local lv = LuaValue(v) if lv then local dv if default then local ok2, d = pcall(function() return default[name] end) if ok2 and d ~= nil then dv = LuaValue(d) end end if name == "Name" or lv ~= dv then table.insert( lines, inner .. var .. "." .. name .. " = " .. lv ) end end end end end end for _, child in ipairs(obj:GetChildren()) do if Listed(child) then Generate( child, depth + 1, var, lines, state ) end end table.insert( lines, inner .. var .. ".Parent = " .. parentVar ) table.insert( lines, pad .. "end" ) end local function ExtractCode() local lines = { 'local ScreenGui = Instance.new("ScreenGui")', 'ScreenGui.Name = "GeneratedGUI"', "ScreenGui.ResetOnSpawn = false", 'ScreenGui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling', 'ScreenGui.Parent = game:GetService("Players").LocalPlayer:WaitForChild("PlayerGui")', "", 'local Canvas = Instance.new("Frame")', 'Canvas.Name = "Canvas"', "Canvas.AnchorPoint = Vector2.new(0.5, 0.5)", "Canvas.Position = UDim2.new(0.5, 0, 0.5, 0)", "Canvas.Size = UDim2.new(0, 700, 0, 450)", "Canvas.BackgroundTransparency = 1", "Canvas.BorderSizePixel = 0", "Canvas.Parent = ScreenGui", "", } local state = { n = 0 } for _, obj in ipairs(Canvas:GetChildren()) do if Listed(obj) then Generate( obj, 0, "Canvas", lines, state ) table.insert(lines, "") end end for k, inst in pairs(DefaultCache) do if inst then inst:Destroy() end DefaultCache[k] = nil end local source = table.concat( lines, "\n" ) UI.CodeBox.Text = source UI.Code.Visible = true if setclipboard then local ok = pcall( setclipboard, source ) if ok then Notify( "Luau copied to clipboard!", Theme.Success ) return end end Notify( "Code generated", Theme.Accent ) end do local copyBtn = Button({ Size = UDim2.new(1, -6, 0, 32), Text = "Copy to clipboard", TextSize = 13, LayoutOrder = 1, }, UI.CodeBody, Theme.AccentDark, Theme.Accent) UI.CodeBox = New("TextBox", { Size = UDim2.new(1, -6, 0, 0), AutomaticSize = Enum.AutomaticSize.Y, BackgroundColor3 = Theme.Bg, BorderSizePixel = 0, TextColor3 = Theme.Text, TextSize = 12, Font = Enum.Font.Code, MultiLine = true, TextWrapped = true, ClearTextOnFocus = false, TextXAlignment = Enum.TextXAlignment.Left, TextYAlignment = Enum.TextYAlignment.Top, Text = "", LayoutOrder = 2, }, UI.CodeBody) Corner(UI.CodeBox, 6) Pad(UI.CodeBox, 8, 8, 8, 8) copyBtn.MouseButton1Click:Connect(function() if setclipboard then local ok = pcall( setclipboard, UI.CodeBox.Text ) if ok then Notify( "Copied!", Theme.Success ) return end end Notify( "Clipboard unavailable - copy manually", Theme.Danger ) end) end do local bar = New("Frame", { Name = "Toolbar", Size = UDim2.new(1, 0, 0, 52), BackgroundColor3 = Theme.Panel, BorderSizePixel = 0, Active = true, ZIndex = 10, }, ScreenGui) Stroke(bar, Theme.Stroke, 1) local scroll = New("ScrollingFrame", { Position = UDim2.fromOffset(8, 0), Size = UDim2.new(1, -16, 1, 0), BackgroundTransparency = 1, BorderSizePixel = 0, ScrollBarThickness = 0, ScrollingDirection = Enum.ScrollingDirection.X, CanvasSize = UDim2.new(), AutomaticCanvasSize = Enum.AutomaticSize.X, }, bar) New("UIListLayout", { FillDirection = Enum.FillDirection.Horizontal, VerticalAlignment = Enum.VerticalAlignment.Center, SortOrder = Enum.SortOrder.LayoutOrder, Padding = UDim.new(0, 6), }, scroll) local order = 0 local function ToolButton( text, width, base, hover ) order += 1 return Button({ Size = UDim2.fromOffset(width, 34), Text = text, TextSize = 12, LayoutOrder = order, }, scroll, base, hover) end order += 1 New("TextLabel", { Size = UDim2.fromOffset(104, 34), BackgroundTransparency = 1, Text = "GUI Studio", TextColor3 = Theme.Accent, TextSize = 15, Font = Enum.Font.GothamBold, LayoutOrder = order, }, scroll) local btnExplorer = ToolButton( "Explorer", 78 ) local btnAdd = ToolButton( "+ Add", 66, Theme.AccentDark, Theme.Accent ) UI.BtnStyle = ToolButton( "Style", 62 ) UI.BtnDup = ToolButton( "Duplicate", 80 ) UI.BtnDel = ToolButton( "Delete", 66, Theme.DangerDark, Theme.Danger ) UI.BtnProps = ToolButton( "Props", 62 ) local btnExtract = ToolButton( "Extract", 74, Color3.fromRGB(30, 140, 85), Theme.Success ) btnExplorer.MouseButton1Click:Connect(function() CloseMenus() UI.Explorer.Visible = not UI.Explorer.Visible if UI.Explorer.Visible then RefreshExplorer() end end) btnAdd.MouseButton1Click:Connect(function() OpenPopup( UI.AddMenu, btnAdd ) end) UI.BtnStyle.MouseButton1Click:Connect(function() OpenPopup( UI.StyleMenu, UI.BtnStyle ) end) UI.BtnDup.MouseButton1Click:Connect(function() CloseMenus() DuplicateSelected() end) UI.BtnDel.MouseButton1Click:Connect(function() CloseMenus() DeleteSelected() end) UI.BtnProps.MouseButton1Click:Connect(function() CloseMenus() UI.Props.Visible = not UI.Props.Visible if UI.Props.Visible then BuildProperties() end end) btnExtract.MouseButton1Click:Connect(function() CloseMenus() ExtractCode() end) end Handle.InputBegan:Connect(function(input) if not GuiTarget or not IsClick(input) then return end Drag.mode = "resize" Drag.obj = GuiTarget Drag.start = input.Position Drag.origin = GuiTarget.Size end) Track(UserInputService.InputChanged:Connect(function(input) if not Drag.mode or not IsMove(input) then return end local obj = Drag.obj if not obj or not obj.Parent then Drag.mode = nil return end local d = input.Position - Drag.start if Drag.mode == "move" then if not Drag.moved and d.Magnitude < 3 then return end Drag.moved = true local o = Drag.origin obj.Position = UDim2.new( o.X.Scale, math.round(o.X.Offset + d.X), o.Y.Scale, math.round(o.Y.Offset + d.Y) ) elseif Drag.mode == "resize" then local o = Drag.origin local nx = math.round( o.X.Offset + d.X ) local ny = math.round( o.Y.Offset + d.Y ) if o.X.Scale == 0 then nx = math.max(8, nx) end if o.Y.Scale == 0 then ny = math.max(8, ny) end obj.Size = UDim2.new( o.X.Scale, nx, o.Y.Scale, ny ) end end)) Track(UserInputService.InputEnded:Connect(function(input) if IsClick(input) and Drag.mode then Drag.mode = nil RefreshProperties() end end)) Track(UserInputService.InputBegan:Connect(function(input, processed) if UserInputService:GetFocusedTextBox() then return end if input.KeyCode == Enum.KeyCode.Delete or input.KeyCode == Enum.KeyCode.Backspace then DeleteSelected() elseif input.KeyCode == Enum.KeyCode.D and ( UserInputService:IsKeyDown(Enum.KeyCode.LeftControl) or UserInputService:IsKeyDown(Enum.KeyCode.RightControl) ) then DuplicateSelected() elseif input.KeyCode == Enum.KeyCode.Escape then CloseMenus() SetSelected(nil) end end)) local lastRefresh = 0 Track(RunService.RenderStepped:Connect(function() if Selected and not Selected:IsDescendantOf(Canvas) then SetSelected(nil) end UpdateSelection() if Drag.mode and os.clock() - lastRefresh > 0.1 then lastRefresh = os.clock() RefreshProperties() end end)) local first = CreateObject( "Frame", Canvas ) AddModifierTo( first, "UICorner" ) AddModifierTo( first, "UIStroke" ) SetSelected(first) RefreshExplorer()