Shop UI Roblox GUI Template with Gamepass & Devproduct Ready
A general-purpose shop GUI with category tabs, item grid, and purchase prompts wired to MarketplaceService. Supports both Gamepasses and Developer Products. Features a clean bright design with animated purchase flow, category filtering, and detailed item descriptions. Ready for monetization out of the box.

Live preview
Shop UI
1920×1080Includes real, production-ready Luau logic — not a static mockup.
What's inside
- • Category tabs (Gear, Power-ups, Skins)
- • UIGridLayout item grid
- • Purchase prompt integration
- • Server validation stub
- • Mobile-friendly scaling
How to use this template
The Shop UI template is a general-purpose shop for Gamepasses and Developer Products. Paste the client Luau into StarterGui and a shop panel appears with category tabs (Gear, Power-ups, Skins) and an item grid. Each item card has a Buy button that calls MarketplaceService:PromptProductPurchase or PromptGamepassPurchase, depending on the item type. The server Luau stub shows how to handle purchase receipts and grant the item. The layout uses UIGridLayout with Scale-based sizing, so it works on mobile and desktop. To customize, replace the placeholder item data with your own product IDs and icons. The category tabs filter the grid by item type - add or remove tabs by editing the tab list in the client Luau. Test the purchase flow in Studio by clicking Buy and confirming the Roblox purchase prompt appears.
Add it to your game in 3 steps
- 1
Copy the Luau
Open the template in the web editor and click Export. Choose LocalScript to copy the full client Luau to your clipboard.
- 2
Paste into StarterGui
In Roblox Studio, right-click StarterGui in the Explorer, insert a LocalScript, and paste the copied Luau. Rename it to match the template.
- 3
Press Play to verify
Click Play in Studio. The GUI should appear exactly as designed. Tweak any Size or Position values in the script if you want to adjust the layout.
1--[[2 Shop UI System - Client3 Features: Category tabs, item grid, MarketplaceService integration, purchase prompts4 Place in: StarterPlayer > StarterPlayerScripts5--]]67local Players = game:GetService("Players")8local TweenService = game:GetService("TweenService")9local UserInputService = game:GetService("UserInputService")10local ReplicatedStorage = game:GetService("ReplicatedStorage")11local MarketplaceService = game:GetService("MarketplaceService")12local RunService = game:GetService("RunService")1314local player = Players.LocalPlayer15local playerGui = player:WaitForChild("PlayerGui")1617-- Remotes18local ShopRemotes = ReplicatedStorage:WaitForChild("ShopRemotes")19local RequestShopData = ShopRemotes:WaitForChild("RequestShopData")20local NotifyPurchase = ShopRemotes:WaitForChild("NotifyPurchase")2122-- ============================================23-- CONFIGURATION24-- ============================================25local CONFIG = {26 AnimSpeed = 0.25,27 CardHoverScale = 1.03,28 ItemsPerRow = 3,29 Categories = {30 {Id = "Featured", Label = "Featured", Icon = "rbxassetid://0", Color = Color3.fromRGB(255, 180, 50)},31 {Id = "Gamepasses", Label = "Gamepasses", Icon = "rbxassetid://0", Color = Color3.fromRGB(100, 150, 255)},32 {Id = "Currency", Label = "Currency", Icon = "rbxassetid://0", Color = Color3.fromRGB(50, 200, 100)},33 {Id = "Boosts", Label = "Boosts", Icon = "rbxassetid://0", Color = Color3.fromRGB(255, 80, 80)},34 {Id = "Cosmetics", Label = "Cosmetics", Icon = "rbxassetid://0", Color = Color3.fromRGB(200, 100, 255)},35 },36 CurrencyTypeColors = {37 Robux = Color3.fromRGB(100, 220, 100),38 Coins = Color3.fromRGB(255, 200, 50),39 Gems = Color3.fromRGB(100, 200, 255),40 },41}4243-- ============================================44-- STATE45-- ============================================46local State = {47 IsVisible = false,48 CurrentCategory = "Featured",49 ShopItems = {},50 OwnedGamepasses = {},51 SelectedItem = nil,52 CoinBalance = 0,53 GemBalance = 0,54}5556-- ============================================57-- UTILITY58-- ============================================59local function Create(className, properties)60 local instance = Instance.new(className)61 for key, value in pairs(properties or {}) do62 instance[key] = value63 end64 return instance65end6667local function Tween(instance, properties, duration, easingStyle, easingDirection)68 local tween = TweenService:Create(69 instance,70 TweenInfo.new(71 duration or CONFIG.AnimSpeed,72 easingStyle or Enum.EasingStyle.Quad,73 easingDirection or Enum.EasingDirection.Out74 ),75 properties76 )77 tween:Play()78 return tween79end8081local function TweenBounce(instance, properties, duration)82 return Tween(instance, properties, duration, Enum.EasingStyle.Back, Enum.EasingDirection.Out)83end8485local function FormatNumber(num)86 if num >= 1000000 then return string.format("%.1fM", num / 1000000)87 elseif num >= 1000 then return string.format("%.1fK", num / 1000)88 else return tostring(num) end89end9091-- ============================================92-- UI CONSTRUCTION93-- ============================================94local UI = {}9596function UI.Build()97 -- ScreenGui98 local screenGui = Create("ScreenGui", {99 Name = "ShopUiGui",100 Parent = playerGui,101 ResetOnSpawn = false,102 ZIndexBehavior = Enum.ZIndexBehavior.Sibling,103 Enabled = false,104 })105 UI.ScreenGui = screenGui106107 -- Background Dim108 local bgDim = Create("Frame", {109 Name = "BackgroundDim",110 Parent = screenGui,111 Size = UDim2.new(1, 0, 1, 0),112 BackgroundColor3 = Color3.fromRGB(0, 0, 0),113 BackgroundTransparency = 0.45,114 BorderSizePixel = 0,115 ZIndex = 1,116 })117118 -- Main Frame119 local mainFrame = Create("Frame", {120 Name = "MainFrame",121 Parent = screenGui,122 AnchorPoint = Vector2.new(0.5, 0.5),123 Position = UDim2.new(0.5, 0, 0.5, 0),124 Size = UDim2.new(0, 600, 0, 440),125 BackgroundColor3 = Color3.fromRGB(245, 245, 255),126 BorderSizePixel = 0,127 ClipsDescendants = true,128 ZIndex = 10,129 })130 UI.MainFrame = mainFrame131132 Create("UICorner", {CornerRadius = UDim.new(0, 14), Parent = mainFrame})133 Create("UIGradient", {134 Color = ColorSequence.new({135 ColorSequenceKeypoint.new(0, Color3.fromRGB(250, 250, 255)),136 ColorSequenceKeypoint.new(1, Color3.fromRGB(235, 238, 250)),137 }),138 Rotation = 135,139 Parent = mainFrame,140 })141142 -- Header Bar143 local headerBar = Create("Frame", {144 Name = "HeaderBar",145 Parent = mainFrame,146 Size = UDim2.new(1, 0, 0, 54),147 BackgroundColor3 = Color3.fromRGB(60, 65, 100),148 BorderSizePixel = 0,149 ZIndex = 11,150 })151152 -- Shop Title153 Create("TextLabel", {154 Name = "ShopTitle",155 Parent = headerBar,156 Position = UDim2.new(0, 18, 0, 0),157 Size = UDim2.new(0, 180, 1, 0),158 BackgroundTransparency = 1,159 Text = "STORE",160 TextColor3 = Color3.fromRGB(255, 255, 255),161 TextSize = 24,162 Font = Enum.Font.GothamBlack,163 TextXAlignment = Enum.TextXAlignment.Left,164 ZIndex = 12,165 })166167 -- Currency Frame168 local currencyFrame = Create("Frame", {169 Name = "CurrencyFrame",170 Parent = headerBar,171 Position = UDim2.new(1, -250, 0.5, -15),172 Size = UDim2.new(0, 200, 0, 32),173 BackgroundColor3 = Color3.fromRGB(45, 50, 80),174 BorderSizePixel = 0,175 ZIndex = 12,176 })177 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = currencyFrame})178179 -- Gems Amount180 UI.GemsAmount = Create("TextLabel", {181 Name = "GemsAmount",182 Parent = currencyFrame,183 Position = UDim2.new(0, 30, 0, 0),184 Size = UDim2.new(0, 80, 1, 0),185 BackgroundTransparency = 1,186 Text = "1,250",187 TextColor3 = Color3.fromRGB(80, 200, 255),188 TextSize = 16,189 Font = Enum.Font.GothamBold,190 ZIndex = 13,191 })192193 -- Coins Amount194 UI.CoinsAmount = Create("TextLabel", {195 Name = "CoinsAmount",196 Parent = currencyFrame,197 Position = UDim2.new(0, 120, 0, 0),198 Size = UDim2.new(0, 80, 1, 0),199 BackgroundTransparency = 1,200 Text = "5,000",201 TextColor3 = Color3.fromRGB(255, 200, 50),202 TextSize = 16,203 Font = Enum.Font.GothamBold,204 ZIndex = 13,205 })206207 -- Close Button208 local closeButton = Create("TextButton", {209 Name = "CloseButton",210 Parent = headerBar,211 Position = UDim2.new(1, -42, 0, 10),212 Size = UDim2.new(0, 30, 0, 30),213 BackgroundColor3 = Color3.fromRGB(220, 70, 70),214 Text = "X",215 TextColor3 = Color3.fromRGB(255, 255, 255),216 TextSize = 16,217 Font = Enum.Font.GothamBold,218 ZIndex = 12,219 })220 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = closeButton})221222 -- Category Tabs223 local tabsFrame = Create("Frame", {224 Name = "CategoryTabs",225 Parent = mainFrame,226 Position = UDim2.new(0, 0, 0, 54),227 Size = UDim2.new(1, 0, 0, 42),228 BackgroundColor3 = Color3.fromRGB(70, 75, 110),229 BorderSizePixel = 0,230 ZIndex = 11,231 })232 Create("UIListLayout", {233 FillDirection = Enum.FillDirection.Horizontal,234 HorizontalAlignment = Enum.HorizontalAlignment.Center,235 VerticalAlignment = Enum.VerticalAlignment.Center,236 Padding = UDim.new(0, 6),237 Parent = tabsFrame,238 })239240 UI.Tabs = {}241 for _, cat in ipairs(CONFIG.Categories) do242 local tabBtn = Create("TextButton", {243 Name = cat.Id .. "Tab",244 Parent = tabsFrame,245 Size = UDim2.new(0, 110, 0, 32),246 BackgroundColor3 = cat.Id == "Featured" and Color3.fromRGB(85, 90, 130) or Color3.fromRGB(60, 65, 100),247 Text = " " .. cat.Label,248 TextColor3 = cat.Id == "Featured" and Color3.fromRGB(255, 255, 255) or Color3.fromRGB(200, 200, 220),249 TextSize = 14,250 Font = Enum.Font.GothamBold,251 ZIndex = 12,252 })253 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = tabBtn})254 UI.Tabs[cat.Id] = {Button = tabBtn, Color = cat.Color}255 end256257 -- Item Grid258 local itemGrid = Create("ScrollingFrame", {259 Name = "ItemGrid",260 Parent = mainFrame,261 Position = UDim2.new(0, 10, 0, 100),262 Size = UDim2.new(1, -20, 1, -110),263 BackgroundTransparency = 1,264 ScrollBarThickness = 6,265 ScrollBarImageColor3 = Color3.fromRGB(120, 120, 140),266 CanvasSize = UDim2.new(0, 0, 0, 0),267 ZIndex = 11,268 })269 UI.ItemGrid = itemGrid270271 Create("UIGridLayout", {272 CellSize = UDim2.new(0, 190, 0, 210),273 CellPadding = UDim2.new(0, 10, 0, 10),274 SortOrder = Enum.SortOrder.Name,275 Parent = itemGrid,276 })277278 -- Purchase Prompt Overlay279 local purchasePrompt = Create("Frame", {280 Name = "PurchasePrompt",281 Parent = screenGui,282 AnchorPoint = Vector2.new(0.5, 0.5),283 Position = UDim2.new(0.5, 0, 0.5, 0),284 Size = UDim2.new(0, 360, 0, 320),285 BackgroundColor3 = Color3.fromRGB(250, 250, 255),286 BorderSizePixel = 0,287 Visible = false,288 ZIndex = 200,289 })290 UI.PurchasePrompt = purchasePrompt291 Create("UICorner", {CornerRadius = UDim.new(0, 16), Parent = purchasePrompt})292 Create("UIStroke", {Color = Color3.fromRGB(60, 180, 80), Thickness = 2, Parent = purchasePrompt})293294 Create("TextLabel", {295 Name = "PromptTitle",296 Parent = purchasePrompt,297 Position = UDim2.new(0, 0, 0, 12),298 Size = UDim2.new(1, 0, 0, 30),299 BackgroundTransparency = 1,300 Text = "CONFIRM PURCHASE",301 TextColor3 = Color3.fromRGB(50, 55, 90),302 TextSize = 22,303 Font = Enum.Font.GothamBlack,304 ZIndex = 201,305 })306307 UI.PromptImage = Create("ImageLabel", {308 Name = "PromptImage",309 Parent = purchasePrompt,310 Position = UDim2.new(0.5, -55, 0, 48),311 Size = UDim2.new(0, 110, 0, 110),312 BackgroundTransparency = 1,313 Image = "",314 ZIndex = 201,315 })316317 UI.PromptName = Create("TextLabel", {318 Name = "PromptName",319 Parent = purchasePrompt,320 Position = UDim2.new(0, 0, 0, 165),321 Size = UDim2.new(1, 0, 0, 26),322 BackgroundTransparency = 1,323 Text = "Item Name",324 TextColor3 = Color3.fromRGB(50, 55, 90),325 TextSize = 20,326 Font = Enum.Font.GothamBold,327 ZIndex = 201,328 })329330 UI.PromptDesc = Create("TextLabel", {331 Name = "PromptDesc",332 Parent = purchasePrompt,333 Position = UDim2.new(0, 15, 0, 193),334 Size = UDim2.new(1, -30, 0, 20),335 BackgroundTransparency = 1,336 Text = "Item description",337 TextColor3 = Color3.fromRGB(120, 120, 140),338 TextSize = 13,339 Font = Enum.Font.Gotham,340 ZIndex = 201,341 })342343 UI.PromptPrice = Create("TextLabel", {344 Name = "PromptPrice",345 Parent = purchasePrompt,346 Position = UDim2.new(0, 0, 0, 218),347 Size = UDim2.new(1, 0, 0, 22),348 BackgroundTransparency = 1,349 Text = "R$ 99",350 TextColor3 = Color3.fromRGB(80, 180, 80),351 TextSize = 18,352 Font = Enum.Font.GothamBlack,353 ZIndex = 201,354 })355356 local buyRobuxBtn = Create("TextButton", {357 Name = "BuyRobuxButton",358 Parent = purchasePrompt,359 Position = UDim2.new(0, 20, 0, 255),360 Size = UDim2.new(0, 155, 0, 42),361 BackgroundColor3 = Color3.fromRGB(60, 180, 80),362 Text = "PURCHASE",363 TextColor3 = Color3.fromRGB(255, 255, 255),364 TextSize = 16,365 Font = Enum.Font.GothamBlack,366 ZIndex = 201,367 })368 Create("UICorner", {CornerRadius = UDim.new(0, 10), Parent = buyRobuxBtn})369 UI.BuyRobuxButton = buyRobuxBtn370371 local cancelBtn = Create("TextButton", {372 Name = "CancelButton",373 Parent = purchasePrompt,374 Position = UDim2.new(0, 185, 0, 255),375 Size = UDim2.new(0, 155, 0, 42),376 BackgroundColor3 = Color3.fromRGB(180, 70, 70),377 Text = "CANCEL",378 TextColor3 = Color3.fromRGB(255, 255, 255),379 TextSize = 16,380 Font = Enum.Font.GothamBlack,381 ZIndex = 201,382 })383 Create("UICorner", {CornerRadius = UDim.new(0, 10), Parent = cancelBtn})384 UI.CancelPromptButton = cancelBtn385386 -- Toast Notification387 UI.ToastFrame = Create("Frame", {388 Name = "ToastNotification",389 Parent = screenGui,390 AnchorPoint = Vector2.new(1, 1),391 Position = UDim2.new(1, -15, 1, 80),392 Size = UDim2.new(0, 280, 0, 50),393 BackgroundColor3 = Color3.fromRGB(60, 180, 80),394 BorderSizePixel = 0,395 Visible = false,396 ZIndex = 500,397 })398 Create("UICorner", {CornerRadius = UDim.new(0, 12), Parent = UI.ToastFrame})399 UI.ToastText = Create("TextLabel", {400 Name = "ToastText",401 Parent = UI.ToastFrame,402 Position = UDim2.new(0, 15, 0, 0),403 Size = UDim2.new(1, -30, 1, 0),404 BackgroundTransparency = 1,405 Text = "Purchase successful!",406 TextColor3 = Color3.fromRGB(255, 255, 255),407 TextSize = 14,408 Font = Enum.Font.GothamBold,409 ZIndex = 501,410 })411412 return UI413end414415-- ============================================416-- ITEM CARD CREATION417-- ============================================418function UI.CreateItemCard(itemData, index)419 local card = Create("Frame", {420 Name = "ItemCard_" .. string.format("%02d", index),421 Parent = UI.ItemGrid,422 Size = UDim2.new(0, 190, 0, 210),423 BackgroundColor3 = Color3.fromRGB(255, 255, 255),424 BorderSizePixel = 0,425 ZIndex = 12,426 })427 Create("UICorner", {CornerRadius = UDim.new(0, 10), Parent = card})428 Create("UIStroke", {429 Color = Color3.fromRGB(200, 205, 220),430 Thickness = 1,431 Parent = card,432 })433434 -- Featured badge (if featured)435 if itemData.Featured then436 local badge = Create("Frame", {437 Name = "FeaturedBadge",438 Parent = card,439 Position = UDim2.new(0, 6, 0, 6),440 Size = UDim2.new(0, 65, 0, 20),441 BackgroundColor3 = Color3.fromRGB(255, 160, 30),442 BorderSizePixel = 0,443 ZIndex = 14,444 })445 Create("UICorner", {CornerRadius = UDim.new(0, 6), Parent = badge})446 Create("TextLabel", {447 Parent = badge,448 Size = UDim2.new(1, 0, 1, 0),449 BackgroundTransparency = 1,450 Text = "FEATURED",451 TextColor3 = Color3.fromRGB(255, 255, 255),452 TextSize = 10,453 Font = Enum.Font.GothamBold,454 ZIndex = 15,455 })456 end457458 -- Item Image459 local itemImage = Create("ImageLabel", {460 Name = "ItemImage",461 Parent = card,462 Position = UDim2.new(0.5, -55, 0, 10),463 Size = UDim2.new(0, 110, 0, 100),464 BackgroundTransparency = 1,465 Image = itemData.Icon or "",466 ZIndex = 13,467 })468469 -- Item Name470 Create("TextLabel", {471 Name = "ItemName",472 Parent = card,473 Position = UDim2.new(0, 0, 0, 116),474 Size = UDim2.new(1, 0, 0, 22),475 BackgroundTransparency = 1,476 Text = itemData.Name or "Unknown",477 TextColor3 = Color3.fromRGB(50, 55, 80),478 TextSize = 15,479 Font = Enum.Font.GothamBold,480 ZIndex = 13,481 })482483 -- Item Description484 Create("TextLabel", {485 Name = "ItemDesc",486 Parent = card,487 Position = UDim2.new(0, 8, 0, 138),488 Size = UDim2.new(1, -16, 0, 16),489 BackgroundTransparency = 1,490 Text = itemData.Description or "",491 TextColor3 = Color3.fromRGB(130, 130, 150),492 TextSize = 11,493 Font = Enum.Font.Gotham,494 TextWrapped = true,495 ZIndex = 13,496 })497498 -- Price Frame499 local priceColor = CONFIG.CurrencyTypeColors[itemData.CurrencyType or "Robux"] or CONFIG.CurrencyTypeColors.Robux500 local priceBtn = Create("TextButton", {501 Name = "PriceButton",502 Parent = card,503 Position = UDim2.new(0.5, -70, 0, 162),504 Size = UDim2.new(0, 140, 0, 36),505 BackgroundColor3 = priceColor,506 Text = " " .. FormatNumber(itemData.Price),507 TextColor3 = Color3.fromRGB(255, 255, 255),508 TextSize = 15,509 Font = Enum.Font.GothamBold,510 ZIndex = 13,511 })512 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = priceBtn})513514 -- Owned badge for gamepasses515 if itemData.Type == "Gamepass" and itemData.Owned then516 priceBtn.Visible = false517 local ownedBadge = Create("Frame", {518 Name = "OwnedBadge",519 Parent = card,520 Position = UDim2.new(0.5, -50, 0, 162),521 Size = UDim2.new(0, 100, 0, 32),522 BackgroundColor3 = Color3.fromRGB(100, 180, 100),523 BorderSizePixel = 0,524 ZIndex = 13,525 })526 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = ownedBadge})527 Create("TextLabel", {528 Parent = ownedBadge,529 Size = UDim2.new(1, 0, 1, 0),530 BackgroundTransparency = 1,531 Text = "OWNED",532 TextColor3 = Color3.fromRGB(255, 255, 255),533 TextSize = 13,534 Font = Enum.Font.GothamBold,535 ZIndex = 14,536 })537 end538539 return {540 Frame = card,541 PriceButton = priceBtn,542 Data = itemData,543 }544end545546-- ============================================547-- LOGIC548-- ============================================549local Logic = {}550551function Logic.SetupInteractions()552 -- Close button553 UI.MainFrame.HeaderBar.CloseButton.MouseButton1Click:Connect(function()554 Logic.Hide()555 end)556557 -- Category tabs558 for catId, tabData in pairs(UI.Tabs) do559 tabData.Button.MouseButton1Click:Connect(function()560 Logic.SetCategory(catId)561 end)562 end563564 -- Purchase prompt buttons565 UI.BuyRobuxButton.MouseButton1Click:Connect(function()566 Logic.ConfirmPurchase()567 end)568 UI.CancelPromptButton.MouseButton1Click:Connect(function()569 Logic.HidePurchasePrompt()570 end)571572 -- MarketplaceService callbacks573 MarketplaceService.PromptGamePassPurchaseFinished:Connect(function(player, gamePassId, wasPurchased)574 if player == Players.LocalPlayer and wasPurchased then575 Logic.ShowToast("Gamepass purchased successfully!")576 Logic.RefreshShop()577 end578 end)579580 MarketplaceService.PromptProductPurchaseFinished:Connect(function(userId, productId, wasPurchased)581 if userId == Players.LocalPlayer.UserId and wasPurchased then582 Logic.ShowToast("Purchase completed!")583 Logic.RefreshBalances()584 end585 end)586end587588function Logic.LoadShopData()589 -- Demo data - in production: RequestShopData:InvokeServer()590 State.ShopItems = {591 -- Featured592 {593 Id = "vip_pass",594 Name = "VIP Pass",595 Description = "Exclusive VIP perks and bonuses!",596 Category = "Gamepasses",597 Type = "Gamepass",598 Price = 399,599 CurrencyType = "Robux",600 Icon = "rbxassetid://0",601 Featured = true,602 GamepassId = 12345678,603 Owned = false,604 },605 {606 Id = "starter_pack",607 Name = "Starter Pack",608 Description = "Perfect for new players!",609 Category = "Featured",610 Type = "Product",611 Price = 49,612 CurrencyType = "Robux",613 Icon = "rbxassetid://0",614 Featured = true,615 ProductId = 87654321,616 },617 -- Gamepasses618 {619 Id = "2x_coins",620 Name = "2x Coins",621 Description = "Double coins forever!",622 Category = "Gamepasses",623 Type = "Gamepass",624 Price = 249,625 CurrencyType = "Robux",626 Icon = "rbxassetid://0",627 GamepassId = 12345679,628 Owned = false,629 },630 {631 Id = "2x_xp",632 Name = "2x XP Boost",633 Description = "Level up twice as fast!",634 Category = "Gamepasses",635 Type = "Gamepass",636 Price = 299,637 CurrencyType = "Robux",638 Icon = "rbxassetid://0",639 GamepassId = 12345680,640 Owned = false,641 },642 -- Currency643 {644 Id = "coins_1k",645 Name = "1,000 Coins",646 Description = "A small coin boost",647 Category = "Currency",648 Type = "Product",649 Price = 49,650 CurrencyType = "Robux",651 Icon = "rbxassetid://0",652 ProductId = 87654322,653 },654 {655 Id = "coins_5k",656 Name = "5,000 Coins",657 Description = "Great value pack!",658 Category = "Currency",659 Type = "Product",660 Price = 199,661 CurrencyType = "Robux",662 Icon = "rbxassetid://0",663 ProductId = 87654323,664 },665 {666 Id = "coins_25k",667 Name = "25,000 Coins",668 Description = "Best deal for coins!",669 Category = "Currency",670 Type = "Product",671 Price = 799,672 CurrencyType = "Robux",673 Icon = "rbxassetid://0",674 ProductId = 87654324,675 },676 -- Boosts677 {678 Id = "speed_boost",679 Name = "Speed Boost",680 Description = "2x speed for 1 hour",681 Category = "Boosts",682 Type = "Product",683 Price = 29,684 CurrencyType = "Robux",685 Icon = "rbxassetid://0",686 ProductId = 87654325,687 },688 {689 Id = "luck_boost",690 Name = "Luck Boost",691 Description = "Better drops for 2 hours",692 Category = "Boosts",693 Type = "Product",694 Price = 39,695 CurrencyType = "Robux",696 Icon = "rbxassetid://0",697 ProductId = 87654326,698 },699 -- Cosmetics700 {701 Id = "rainbow_trail",702 Name = "Rainbow Trail",703 Description = "Leave a rainbow behind!",704 Category = "Cosmetics",705 Type = "Product",706 Price = 149,707 CurrencyType = "Robux",708 Icon = "rbxassetid://0",709 ProductId = 87654327,710 },711 {712 Id = "golden_skin",713 Name = "Golden Skin",714 Description = "Shine like gold!",715 Category = "Cosmetics",716 Type = "Product",717 Price = 99,718 CurrencyType = "Robux",719 Icon = "rbxassetid://0",720 ProductId = 87654328,721 },722 }723724 State.CoinBalance = 5000725 State.GemBalance = 1250726727 Logic.RefreshBalances()728 Logic.RefreshItemGrid()729end730731function Logic.RefreshBalances()732 UI.CoinsAmount.Text = FormatNumber(State.CoinBalance)733 UI.GemsAmount.Text = FormatNumber(State.GemBalance)734end735736function Logic.RefreshItemGrid()737 -- Clear existing738 for _, child in ipairs(UI.ItemGrid:GetChildren()) do739 if child:IsA("Frame") then child:Destroy() end740 end741 UI.ItemCards = {}742743 -- Filter items744 local filtered = {}745 for _, item in ipairs(State.ShopItems) do746 local show = false747 if State.CurrentCategory == "Featured" then748 show = item.Featured or false749 else750 show = item.Category == State.CurrentCategory751 end752 if show then753 table.insert(filtered, item)754 end755 end756757 -- Create cards758 for i, item in ipairs(filtered) do759 local card = UI.CreateItemCard(item, i)760 table.insert(UI.ItemCards, card)761762 -- Card hover763 card.Frame.MouseEnter:Connect(function()764 Tween(card.Frame, {765 Size = UDim2.new(0, 190 * CONFIG.CardHoverScale, 0, 210 * CONFIG.CardHoverScale)766 }, 0.15)767 end)768 card.Frame.MouseLeave:Connect(function()769 Tween(card.Frame, {Size = UDim2.new(0, 190, 0, 210)}, 0.15)770 end)771772 -- Purchase click773 card.PriceButton.MouseButton1Click:Connect(function()774 Logic.OnPurchaseClick(item)775 end)776 end777778 -- Update canvas779 local rows = math.ceil(#filtered / CONFIG.ItemsPerRow)780 UI.ItemGrid.CanvasSize = UDim2.new(0, 0, 0, rows * 220)781end782783function Logic.SetCategory(categoryId)784 State.CurrentCategory = categoryId785786 -- Update tab visuals787 for catId, tabData in pairs(UI.Tabs) do788 local isActive = catId == categoryId789 tabData.Button.BackgroundColor3 = isActive790 and Color3.fromRGB(85, 90, 130) or Color3.fromRGB(60, 65, 100)791 tabData.Button.TextColor3 = isActive792 and Color3.fromRGB(255, 255, 255) or Color3.fromRGB(200, 200, 220)793 end794795 Logic.RefreshItemGrid()796end797798function Logic.OnPurchaseClick(item)799 if item.Type == "Gamepass" and item.GamepassId then800 -- Check if owned801 local isOwned = State.OwnedGamepasses[item.GamepassId]802 if isOwned then803 Logic.ShowToast("You already own this gamepass!")804 return805 end806 -- Prompt gamepass purchase807 MarketplaceService:PromptGamePassPurchase(player, item.GamepassId)808 elseif item.Type == "Product" and item.ProductId then809 -- Store for confirmation810 State.SelectedItem = item811 Logic.ShowPurchasePrompt(item)812 end813end814815function Logic.ShowPurchasePrompt(item)816 UI.PromptImage.Image = item.Icon or ""817 UI.PromptName.Text = item.Name818 UI.PromptDesc.Text = item.Description or ""819820 local priceSymbol = item.CurrencyType == "Robux" and "R$ " or ""821 UI.PromptPrice.Text = priceSymbol .. FormatNumber(item.Price)822 UI.PromptPrice.TextColor3 = CONFIG.CurrencyTypeColors[item.CurrencyType] or CONFIG.CurrencyTypeColors.Robux823824 UI.PurchasePrompt.Visible = true825 UI.PurchasePrompt.Size = UDim2.new(0, 320, 0, 290)826 TweenBounce(UI.PurchasePrompt, {Size = UDim2.new(0, 360, 0, 320)}, 0.3)827end828829function Logic.HidePurchasePrompt()830 Tween(UI.PurchasePrompt, {Size = UDim2.new(0, 320, 0, 290)}, 0.2)831 task.delay(0.2, function()832 UI.PurchasePrompt.Visible = false833 end)834end835836function Logic.ConfirmPurchase()837 if not State.SelectedItem then return end838839 local item = State.SelectedItem840841 if item.Type == "Product" and item.ProductId then842 -- Prompt developer product purchase843 MarketplaceService:PromptProductPurchase(player, item.ProductId)844 end845846 Logic.HidePurchasePrompt()847end848849function Logic.ShowToast(message)850 UI.ToastText.Text = message851 UI.ToastFrame.Visible = true852 UI.ToastFrame.Position = UDim2.new(1, -15, 1, 80)853854 Tween(UI.ToastFrame, {Position = UDim2.new(1, -15, 1, -15)}, 0.3, Enum.EasingStyle.Back, Enum.EasingDirection.Out)855856 task.delay(3, function()857 Tween(UI.ToastFrame, {Position = UDim2.new(1, -15, 1, 80)}, 0.3)858 task.delay(0.3, function()859 UI.ToastFrame.Visible = false860 end)861 end)862end863864function Logic.Show()865 State.IsVisible = true866 UI.ScreenGui.Enabled = true867 UI.MainFrame.Size = UDim2.new(0, 540, 0, 400)868 Tween(UI.MainFrame, {Size = UDim2.new(0, 600, 0, 440)}, 0.3, Enum.EasingStyle.Back, Enum.EasingDirection.Out)869 Logic.LoadShopData()870end871872function Logic.Hide()873 State.IsVisible = false874 Tween(UI.MainFrame, {Size = UDim2.new(0, 540, 0, 400)}, 0.2)875 task.delay(0.2, function()876 if not State.IsVisible then877 UI.ScreenGui.Enabled = false878 end879 end)880end881882function Logic.Toggle()883 if State.IsVisible then Logic.Hide() else Logic.Show() end884end885886-- ============================================887-- INITIALIZATION888-- ============================================889UI.Build()890Logic.SetupInteractions()891892-- Bind to key893UserInputService.InputBegan:Connect(function(input, gameProcessed)894 if gameProcessed then return end895 if input.KeyCode == Enum.KeyCode.B then896 Logic.Toggle()897 end898end)899900print("Shop UI System initialized! Press 'B' to open shop.")
