-- [ Yuri's ArtStudio Toolbox v2 - Busca Corrigida Mobile ] -- local CoreGui = game:GetService("CoreGui") local HttpService = game:GetService("HttpService") local UserInputService = game:GetService("UserInputService") local TweenService = game:GetService("TweenService") local SoundService = game:GetService("SoundService") local Players = game:GetService("Players") -- ========================================== -- CONFIG -- ========================================== local HOSTS = { "apis.roproxy.com", "apis.roblox.com" } -- tenta um, depois o outro local CATEGORIES = { Models = { id = 10, label = "Modelo" }, Decals = { id = 13, label = "Decal" }, Audios = { id = 3, label = "Audio" }, } local RED = Color3.fromRGB(220, 30, 30) local BG = Color3.fromRGB(15, 15, 15) local BG2 = Color3.fromRGB(25, 25, 25) local BG3 = Color3.fromRGB(35, 35, 35) -- ========================================== -- GUI PAI (gethui se existir) -- ========================================== local function GetGuiParent() local ok, h = pcall(function() return gethui and gethui() end) if ok and h then return h end return CoreGui end local parentGui = GetGuiParent() for _, p in ipairs({ CoreGui, parentGui }) do local old = p:FindFirstChild("YuriToolboxPure") if old then old:Destroy() end end local Gui = Instance.new("ScreenGui") Gui.Name = "YuriToolboxPure" Gui.ResetOnSpawn = false Gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling Gui.Parent = parentGui -- ========================================== -- REQUISIÇÃO -- ========================================== local function Http(url) local ok, res = pcall(function() local fn = (syn and syn.request) or request or http_request or (http and http.request) if fn then local r = fn({ Url = url, Method = "GET", Headers = { ["Accept"] = "application/json" } }) if r.StatusCode and r.StatusCode ~= 200 then error("HTTP " .. tostring(r.StatusCode)) end return r.Body end return game:HttpGet(url) end) return ok, res end local function ApiGet(path) local lastErr = "sem resposta" for _, host in ipairs(HOSTS) do local ok, body = Http("https://" .. host .. path) if ok and body and body ~= "" then local okJson, data = pcall(function() return HttpService:JSONDecode(body) end) if okJson and type(data) == "table" then return data end lastErr = "JSON inválido" else lastErr = tostring(body) end end return nil, lastErr end -- ========================================== -- HELPERS UI -- ========================================== local function Corner(obj, r) local c = Instance.new("UICorner") c.CornerRadius = UDim.new(0, r or 6) c.Parent = obj return c end local function Stroke(obj, color, th) local s = Instance.new("UIStroke") s.Color = color or RED s.Thickness = th or 1 s.ApplyStrokeMode = Enum.ApplyStrokeMode.Border s.Parent = obj return s end local function MakeButton(parent, text, color, size, pos) local b = Instance.new("TextButton") b.Size = size b.Position = pos or UDim2.new() b.BackgroundColor3 = color b.TextColor3 = Color3.new(1, 1, 1) b.Text = text b.Font = Enum.Font.GothamBold b.TextSize = 12 b.AutoButtonColor = false b.Parent = parent Corner(b, 6) local base = color b.MouseEnter:Connect(function() TweenService:Create(b, TweenInfo.new(0.12), { BackgroundColor3 = base:Lerp(Color3.new(1, 1, 1), 0.15) }):Play() end) b.MouseLeave:Connect(function() TweenService:Create(b, TweenInfo.new(0.12), { BackgroundColor3 = base }):Play() end) return b end local function MakeDraggable(handle, frame) local dragging, dragStart, startPos handle.InputBegan:Connect(function(input) if input.UserInputType == Enum.UserInputType.MouseButton1 or input.UserInputType == Enum.UserInputType.Touch then dragging = true dragStart = input.Position startPos = frame.Position input.Changed:Connect(function() if input.UserInputState == Enum.UserInputState.End then dragging = false end end) end end) UserInputService.InputChanged:Connect(function(input) if dragging and (input.UserInputType == Enum.UserInputType.MouseMovement or input.UserInputType == Enum.UserInputType.Touch) then local d = input.Position - dragStart frame.Position = UDim2.new(startPos.X.Scale, startPos.X.Offset + d.X, startPos.Y.Scale, startPos.Y.Offset + d.Y) end end) end -- ========================================== -- BOTÃO FLUTUANTE -- ========================================== local OpenBtn = Instance.new("ImageButton") OpenBtn.Size = UDim2.new(0, 50, 0, 50) OpenBtn.Position = UDim2.new(0, 10, 0.5, -25) OpenBtn.BackgroundColor3 = Color3.fromRGB(20, 20, 20) OpenBtn.Image = "rbxassetid://129988823899871" OpenBtn.Parent = Gui Corner(OpenBtn, 10) Stroke(OpenBtn, RED, 2) MakeDraggable(OpenBtn, OpenBtn) -- ========================================== -- JANELA PRINCIPAL -- ========================================== local MainFrame = Instance.new("Frame") MainFrame.Size = UDim2.new(0, 380, 0, 540) MainFrame.Position = UDim2.new(0.5, -190, 0.5, -270) MainFrame.BackgroundColor3 = BG MainFrame.Visible = false MainFrame.ClipsDescendants = true MainFrame.Parent = Gui Corner(MainFrame, 10) Stroke(MainFrame, RED, 2) -- escala automática p/ telas pequenas do local cam = workspace.CurrentCamera if cam then local vp = cam.ViewportSize local scale = math.min(1, (vp.Y - 20) / 540, (vp.X - 20) / 380) if scale < 1 then local us = Instance.new("UIScale") us.Scale = math.max(scale, 0.5) us.Parent = MainFrame end end end OpenBtn.MouseButton1Click:Connect(function() MainFrame.Visible = not MainFrame.Visible end) -- TopBar local TopBar = Instance.new("Frame") TopBar.Size = UDim2.new(1, 0, 0, 36) TopBar.BackgroundColor3 = Color3.fromRGB(22, 22, 22) TopBar.Parent = MainFrame MakeDraggable(TopBar, MainFrame) local Title = Instance.new("TextLabel") Title.Size = UDim2.new(1, -90, 1, 0) Title.Position = UDim2.new(0, 12, 0, 0) Title.BackgroundTransparency = 1 Title.Text = "🎨 YURI STUDIO • Toolbox" Title.TextColor3 = RED Title.Font = Enum.Font.GothamBold Title.TextSize = 15 Title.TextXAlignment = Enum.TextXAlignment.Left Title.Parent = TopBar local CloseBtn = MakeButton(TopBar, "✕", Color3.fromRGB(170, 30, 30), UDim2.new(0, 28, 0, 24), UDim2.new(1, -34, 0, 6)) local MinBtn = MakeButton(TopBar, "—", BG3, UDim2.new(0, 28, 0, 24), UDim2.new(1, -68, 0, 6)) CloseBtn.MouseButton1Click:Connect(function() MainFrame.Visible = false end) -- Corpo (some quando minimizado) local Body = Instance.new("Frame") Body.Size = UDim2.new(1, 0, 1, -36) Body.Position = UDim2.new(0, 0, 0, 36) Body.BackgroundTransparency = 1 Body.Parent = MainFrame local minimized = false MinBtn.MouseButton1Click:Connect(function() minimized = not minimized Body.Visible = not minimized MainFrame.Size = minimized and UDim2.new(0, 380, 0, 36) or UDim2.new(0, 380, 0, 540) end) -- Pesquisa local SearchBox = Instance.new("TextBox") SearchBox.Size = UDim2.new(1, -110, 0, 34) SearchBox.Position = UDim2.new(0, 10, 0, 8) SearchBox.BackgroundColor3 = BG2 SearchBox.TextColor3 = Color3.new(1, 1, 1) SearchBox.PlaceholderText = "🔎 Procurar (ex: npc, zombie...)" SearchBox.PlaceholderColor3 = Color3.fromRGB(120, 120, 120) SearchBox.Font = Enum.Font.Gotham SearchBox.TextSize = 14 SearchBox.Text = "" SearchBox.ClearTextOnFocus = false SearchBox.Parent = Body Corner(SearchBox, 6) Stroke(SearchBox, Color3.fromRGB(60, 60, 60), 1) local SearchBtn = MakeButton(Body, "Buscar", RED, UDim2.new(0, 85, 0, 34), UDim2.new(1, -95, 0, 8)) SearchBtn.TextSize = 14 -- Abas local Tabs = Instance.new("Frame") Tabs.Size = UDim2.new(1, -20, 0, 30) Tabs.Position = UDim2.new(0, 10, 0, 48) Tabs.BackgroundTransparency = 1 Tabs.Parent = Body local TabLayout = Instance.new("UIListLayout") TabLayout.FillDirection = Enum.FillDirection.Horizontal TabLayout.Padding = UDim.new(0, 6) TabLayout.Parent = Tabs local currentCategory = "Models" local tabButtons = {} local function CreateTab(key, txt) local b = MakeButton(Tabs, txt, BG3, UDim2.new(1 / 3, -4, 1, 0)) tabButtons[key] = b return b end CreateTab("Models", "📦 Models") CreateTab("Decals", "🖼️ Decals") CreateTab("Audios", "🔊 Audio") local function UpdateTabColors() for key, b in pairs(tabButtons) do b.BackgroundColor3 = (key == currentCategory) and RED or BG3 end end UpdateTabColors() -- Lista (grid) local Scroll = Instance.new("ScrollingFrame") Scroll.Size = UDim2.new(1, -20, 0, 250) Scroll.Position = UDim2.new(0, 10, 0, 84) Scroll.BackgroundColor3 = Color3.fromRGB(18, 18, 18) Scroll.BorderSizePixel = 0 Scroll.ScrollBarThickness = 4 Scroll.ScrollBarImageColor3 = RED Scroll.AutomaticCanvasSize = Enum.AutomaticSize.Y Scroll.CanvasSize = UDim2.new() Scroll.Parent = Body Corner(Scroll, 6) local Pad = Instance.new("UIPadding") Pad.PaddingTop = UDim.new(0, 6) Pad.PaddingLeft = UDim.new(0, 6) Pad.PaddingRight = UDim.new(0, 6) Pad.PaddingBottom = UDim.new(0, 6) Pad.Parent = Scroll local Grid = Instance.new("UIGridLayout") Grid.CellSize = UDim2.new(0, 80, 0, 100) Grid.CellPadding = UDim2.new(0, 6, 0, 6) Grid.SortOrder = Enum.SortOrder.LayoutOrder Grid.Parent = Scroll -- Barra de status + carregar mais local StatusLbl = Instance.new("TextLabel") StatusLbl.Size = UDim2.new(1, -130, 0, 26) StatusLbl.Position = UDim2.new(0, 12, 0, 340) StatusLbl.BackgroundTransparency = 1 StatusLbl.TextColor3 = Color3.fromRGB(170, 170, 170) StatusLbl.Font = Enum.Font.Gotham StatusLbl.TextSize = 11 StatusLbl.TextWrapped = true StatusLbl.TextXAlignment = Enum.TextXAlignment.Left StatusLbl.Text = "Digite algo e toque em Buscar." StatusLbl.Parent = Body local LoadMoreBtn = MakeButton(Body, "Mais ▼", BG3, UDim2.new(0, 105, 0, 26), UDim2.new(1, -115, 0, 340)) LoadMoreBtn.Visible = false local function SetStatus(txt, color) StatusLbl.Text = txt StatusLbl.TextColor3 = color or Color3.fromRGB(170, 170, 170) end -- Inspetor local Inspector = Instance.new("Frame") Inspector.Size = UDim2.new(1, -20, 0, 130) Inspector.Position = UDim2.new(0, 10, 0, 372) Inspector.BackgroundColor3 = Color3.fromRGB(22, 22, 22) Inspector.Parent = Body Corner(Inspector, 8) Stroke(Inspector, RED, 1) local InspThumb = Instance.new("ImageLabel") InspThumb.Size = UDim2.new(0, 70, 0, 70) InspThumb.Position = UDim2.new(0, 8, 0, 8) InspThumb.BackgroundColor3 = BG InspThumb.Parent = Inspector Corner(InspThumb, 6) local InspName = Instance.new("TextLabel") InspName.Size = UDim2.new(1, -96, 0, 24) InspName.Position = UDim2.new(0, 86, 0, 8) InspName.BackgroundTransparency = 1 InspName.Text = "Selecione um ativo" InspName.TextColor3 = Color3.new(1, 1, 1) InspName.Font = Enum.Font.GothamBold InspName.TextSize = 14 InspName.TextXAlignment = Enum.TextXAlignment.Left InspName.TextTruncate = Enum.TextTruncate.AtEnd InspName.Parent = Inspector local InspInfo = Instance.new("TextLabel") InspInfo.Size = UDim2.new(1, -96, 0, 40) InspInfo.Position = UDim2.new(0, 86, 0, 34) InspInfo.BackgroundTransparency = 1 InspInfo.Text = "Tipo: --\nID: --" InspInfo.TextColor3 = Color3.fromRGB(150, 150, 150) InspInfo.Font = Enum.Font.Gotham InspInfo.TextSize = 12 InspInfo.TextXAlignment = Enum.TextXAlignment.Left InspInfo.TextYAlignment = Enum.TextYAlignment.Top InspInfo.Parent = Inspector local BtnRow = Instance.new("Frame") BtnRow.Size = UDim2.new(1, -16, 0, 40) BtnRow.Position = UDim2.new(0, 8, 0, 82) BtnRow.BackgroundTransparency = 1 BtnRow.Parent = Inspector local RowLayout = Instance.new("UIListLayout") RowLayout.FillDirection = Enum.FillDirection.Horizontal RowLayout.Padding = UDim.new(0, 5) RowLayout.Parent = BtnRow local InsertBtn = MakeButton(BtnRow, "➕ Inserir", Color3.fromRGB(0, 150, 0), UDim2.new(0.25, -4, 1, 0)) local CopyBtn = MakeButton(BtnRow, "📋 Copiar ID", Color3.fromRGB(40, 90, 200), UDim2.new(0.25, -4, 1, 0)) local PlayBtn = MakeButton(BtnRow, "▶ Play", Color3.fromRGB(200, 130, 0), UDim2.new(0.25, -4, 1, 0)) local UndoBtn = MakeButton(BtnRow, "↩ Desfazer", Color3.fromRGB(110, 40, 40), UDim2.new(0.25, -4, 1, 0)) -- ========================================== -- ESTADO -- ========================================== local SelectedAsset = nil local SelectedCard = nil local inserted = {} local previewSound = Instance.new("Sound") previewSound.Name = "YuriPreview" previewSound.Volume = 1 previewSound.Parent = SoundService local function Flash(btn, txt, original) btn.Text = txt task.delay(1.2, function() if btn and btn.Parent then btn.Text = original end end) end -- ========================================== -- AÇÕES -- ========================================== CopyBtn.MouseButton1Click:Connect(function() if not SelectedAsset then return SetStatus("Selecione um ativo primeiro.", Color3.fromRGB(255, 120, 120)) end local id = tostring(SelectedAsset.id) local ok = pcall(function() if setclipboard then setclipboard(id) elseif toclipboard then toclipboard(id) elseif Clipboard and Clipboard.set then Clipboard.set(id) else error("sem clipboard") end end) if ok then Flash(CopyBtn, "✔ Copiado!", "📋 Copiar ID") SetStatus("ID " .. id .. " copiado.", Color3.fromRGB(120, 255, 120)) else SetStatus("Seu executor não tem setclipboard. ID: " .. id, Color3.fromRGB(255, 200, 100)) end end) PlayBtn.MouseButton1Click:Connect(function() if not SelectedAsset then return SetStatus("Selecione um ativo primeiro.", Color3.fromRGB(255, 120, 120)) end if SelectedAsset.type ~= "Audio" then return SetStatus("Play só funciona na aba Audio.", Color3.fromRGB(255, 200, 100)) end local sid = "rbxassetid://" .. SelectedAsset.id if previewSound.IsPlaying and previewSound.SoundId == sid then previewSound:Stop() PlayBtn.Text = "▶ Play" else previewSound:Stop() previewSound.SoundId = sid previewSound.TimePosition = 0 previewSound:Play() PlayBtn.Text = "⏹ Stop" SetStatus("Tocando: " .. SelectedAsset.name, Color3.fromRGB(120, 255, 120)) end end) previewSound.Ended:Connect(function() PlayBtn.Text = "▶ Play" end) previewSound.Stopped:Connect(function() PlayBtn.Text = "▶ Play" end) local function PlaceInFront(obj) local char = Players.LocalPlayer and Players.LocalPlayer.Character local root = char and char:FindFirstChild("HumanoidRootPart") if root and (obj:IsA("Model") or obj:IsA("BasePart")) then pcall(function() obj:PivotTo(root.CFrame * CFrame.new(0, 0, -8)) end) end end InsertBtn.MouseButton1Click:Connect(function() if not SelectedAsset then return SetStatus("Selecione um ativo primeiro.", Color3.fromRGB(255, 120, 120)) end local id, atype, name = SelectedAsset.id, SelectedAsset.type, SelectedAsset.name local ok, err = pcall(function() if atype == "Audio" then local snd = Instance.new("Sound") snd.SoundId = "rbxassetid://" .. id snd.Name = name snd.Parent = workspace table.insert(inserted, snd) elseif atype == "Decal" then local part = Instance.new("Part") part.Name = name part.Size = Vector3.new(6, 6, 0.2) part.Anchored = true local d = Instance.new("Decal") d.Texture = "rbxassetid://" .. id d.Face = Enum.NormalId.Front d.Parent = part part.Parent = workspace PlaceInFront(part) table.insert(inserted, part) else local objs = game:GetObjects("rbxassetid://" .. id) for _, o in ipairs(objs) do o.Parent = workspace PlaceInFront(o) table.insert(inserted, o) end end end) if ok then Flash(InsertBtn, "✔ Inserido!", "➕ Inserir") SetStatus("Inserido no workspace: " .. name, Color3.fromRGB(120, 255, 120)) else SetStatus("Falha ao inserir: " .. tostring(err), Color3.fromRGB(255, 120, 120)) end end) UndoBtn.MouseButton1Click:Connect(function() local last = table.remove(inserted) if last then pcall(function() last:Destroy() end) SetStatus("Último item removido.", Color3.fromRGB(255, 200, 100)) else SetStatus("Nada para desfazer.", Color3.fromRGB(255, 120, 120)) end end) -- ========================================== -- BUSCA -- ========================================== local currentQuery = "" local currentCursor = "" local isFetching = false local function SelectAsset(card, thumbImage, id, name, typeStr, hasImage) if SelectedCard and SelectedCard.Parent then local st = SelectedCard:FindFirstChildOfClass("UIStroke") if st then st.Color = Color3.fromRGB(50, 50, 50) end end SelectedCard = card local st = card:FindFirstChildOfClass("UIStroke") if st then st.Color = RED end SelectedAsset = { id = id, name = name, type = typeStr } InspThumb.Image = hasImage and thumbImage or "" InspName.Text = name InspInfo.Text = "Tipo: " .. typeStr .. "\nID: " .. tostring(id) end local function CreateCard(id, name, typeStr) local Card = Instance.new("Frame") Card.BackgroundColor3 = BG2 Card.Parent = Scroll Corner(Card, 6) Stroke(Card, Color3.fromRGB(50, 50, 50), 1) local thumbImg = "rbxthumb://type=Asset&id=" .. id .. "&w=150&h=150" local isAudio = (typeStr == "Audio") local Thumb = Instance.new("ImageLabel") Thumb.Size = UDim2.new(1, -10, 0, 62) Thumb.Position = UDim2.new(0, 5, 0, 5) Thumb.BackgroundColor3 = BG Thumb.Image = isAudio and "" or thumbImg Thumb.ScaleType = Enum.ScaleType.Fit Thumb.Parent = Card Corner(Thumb, 4) if isAudio then local ic = Instance.new("TextLabel") ic.Size = UDim2.new(1, 0, 1, 0) ic.BackgroundTransparency = 1 ic.Text = "🔊" ic.TextSize = 28 ic.Parent = Thumb end local NameLbl = Instance.new("TextLabel") NameLbl.Size = UDim2.new(1, -8, 0, 28) NameLbl.Position = UDim2.new(0, 4, 0, 69) NameLbl.BackgroundTransparency = 1 NameLbl.Text = name NameLbl.TextColor3 = Color3.new(1, 1, 1) NameLbl.Font = Enum.Font.Gotham NameLbl.TextSize = 10 NameLbl.TextWrapped = true NameLbl.TextTruncate = Enum.TextTruncate.AtEnd NameLbl.TextYAlignment = Enum.TextYAlignment.Top NameLbl.Parent = Card local Click = Instance.new("TextButton") Click.Size = UDim2.new(1, 0, 1, 0) Click.BackgroundTransparency = 1 Click.Text = "" Click.ZIndex = 5 Click.Parent = Card Click.MouseButton1Click:Connect(function() SelectAsset(Card, thumbImg, id, name, typeStr, not isAudio) end) end local function ClearCards() for _, c in ipairs(Scroll:GetChildren()) do if c:IsA("Frame") then c:Destroy() end end SelectedCard = nil Scroll.CanvasPosition = Vector2.new(0, 0) end local function FetchAssets(query, append) if isFetching then return end query = (query or ""):gsub("^%s+", ""):gsub("%s+$", "") if query == "" then return SetStatus("Digite algo para buscar.", Color3.fromRGB(255, 200, 100)) end isFetching = true currentQuery = query local cat = CATEGORIES[currentCategory] if not append then ClearCards() currentCursor = "" end SearchBtn.Text = "..." LoadMoreBtn.Visible = false SetStatus("Buscando...", Color3.fromRGB(200, 200, 200)) task.spawn(function() local path = "/toolbox-service/v1/marketplace/" .. cat.id .. "?keyword=" .. HttpService:UrlEncode(query) .. "&limit=30" if currentCursor ~= "" then path = path .. "&cursor=" .. HttpService:UrlEncode(currentCursor) end local data, err = ApiGet(path) if data and type(data.data) == "table" then local ids = {} for _, item in ipairs(data.data) do local id = item.id or (item.asset and item.asset.id) if id then table.insert(ids, id) end end if #ids == 0 then SetStatus("Nada encontrado para: " .. query, Color3.fromRGB(255, 200, 100)) else -- pega os nomes numa segunda rota local names = {} local details = ApiGet("/toolbox-service/v1/items/details?assetIds=" .. table.concat(ids, ",")) if details and type(details.data) == "table" then for _, d in ipairs(details.data) do if d.asset and d.asset.id then names[d.asset.id] = d.asset.name end end end for _, id in ipairs(ids) do CreateCard(id, names[id] or ("Asset " .. id), cat.label) end SetStatus(#ids .. " resultado(s) carregado(s).", Color3.fromRGB(120, 255, 120)) end currentCursor = data.nextPageCursor or "" LoadMoreBtn.Visible = (currentCursor ~= "") else SetStatus("Falha na busca: " .. tostring(err or "resposta inesperada"), Color3.fromRGB(255, 120, 120)) end SearchBtn.Text = "Buscar" isFetching = false end) end -- ========================================== -- EVENTOS -- ========================================== SearchBtn.MouseButton1Click:Connect(function() FetchAssets(SearchBox.Text, false) end) SearchBox.FocusLost:Connect(function(enter) if enter then FetchAssets(SearchBox.Text, false) end end) LoadMoreBtn.MouseButton1Click:Connect(function() if currentCursor ~= "" then FetchAssets(currentQuery, true) end end) for key, btn in pairs(tabButtons) do btn.MouseButton1Click:Connect(function() currentCategory = key UpdateTabColors() if SearchBox.Text ~= "" then FetchAssets(SearchBox.Text, false) end end) end