Roblox GUI Maker logoRoblox GUI Maker
Unofficial third-party tool · Not affiliated with Roblox Corporation

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.

ShopFree
Shop UI Roblox GUI template — Gamepass & Devproduct Ready, bright shop layout, screenshot 1
Shop UI Roblox GUI template — screenshot 1 of 1, showing gamepass & devproduct ready on a bright shop layout for desktop.
Open in Web EditorJoin Studio plugin waitlist

Live preview

Shop UI

1920×1080
Zoom100%
Desktop (FHD)
ScreenGui
Frame
Item Shop
Frame
Gear
Power-ups
Skins
Frame
Frame
Item 1
$Buy
Frame
Frame
Item 2
$Buy
Frame
Frame
Item 3
$Buy
Frame
Frame
Item 4
$Buy
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.

Includes real, production-ready Luau logic — not a static mockup.

What's inside

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. 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. 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. 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.

shop-ui.lua
lua
1--[[
2 Shop UI System - Client
3 Features: Category tabs, item grid, MarketplaceService integration, purchase prompts
4 Place in: StarterPlayer > StarterPlayerScripts
5--]]
6
7local 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")
13
14local player = Players.LocalPlayer
15local playerGui = player:WaitForChild("PlayerGui")
16
17-- Remotes
18local ShopRemotes = ReplicatedStorage:WaitForChild("ShopRemotes")
19local RequestShopData = ShopRemotes:WaitForChild("RequestShopData")
20local NotifyPurchase = ShopRemotes:WaitForChild("NotifyPurchase")
21
22-- ============================================
23-- CONFIGURATION
24-- ============================================
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}
42
43-- ============================================
44-- STATE
45-- ============================================
46local State = {
47 IsVisible = false,
48 CurrentCategory = "Featured",
49 ShopItems = {},
50 OwnedGamepasses = {},
51 SelectedItem = nil,
52 CoinBalance = 0,
53 GemBalance = 0,
54}
55
56-- ============================================
57-- UTILITY
58-- ============================================
59local function Create(className, properties)
60 local instance = Instance.new(className)
61 for key, value in pairs(properties or {}) do
62 instance[key] = value
63 end
64 return instance
65end
66
67local 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.Out
74 ),
75 properties
76 )
77 tween:Play()
78 return tween
79end
80
81local function TweenBounce(instance, properties, duration)
82 return Tween(instance, properties, duration, Enum.EasingStyle.Back, Enum.EasingDirection.Out)
83end
84
85local 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) end
89end
90
91-- ============================================
92-- UI CONSTRUCTION
93-- ============================================
94local UI = {}
95
96function UI.Build()
97 -- ScreenGui
98 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 = screenGui
106
107 -- Background Dim
108 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 })
117
118 -- Main Frame
119 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 = mainFrame
131
132 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 })
141
142 -- Header Bar
143 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 })
151
152 -- Shop Title
153 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 })
166
167 -- Currency Frame
168 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})
178
179 -- Gems Amount
180 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 })
192
193 -- Coins Amount
194 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 })
206
207 -- Close Button
208 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})
221
222 -- Category Tabs
223 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 })
239
240 UI.Tabs = {}
241 for _, cat in ipairs(CONFIG.Categories) do
242 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 end
256
257 -- Item Grid
258 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 = itemGrid
270
271 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 })
277
278 -- Purchase Prompt Overlay
279 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 = purchasePrompt
291 Create("UICorner", {CornerRadius = UDim.new(0, 16), Parent = purchasePrompt})
292 Create("UIStroke", {Color = Color3.fromRGB(60, 180, 80), Thickness = 2, Parent = purchasePrompt})
293
294 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 })
306
307 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 })
316
317 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 })
329
330 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 })
342
343 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 })
355
356 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 = buyRobuxBtn
370
371 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 = cancelBtn
385
386 -- Toast Notification
387 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 })
411
412 return UI
413end
414
415-- ============================================
416-- ITEM CARD CREATION
417-- ============================================
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 })
433
434 -- Featured badge (if featured)
435 if itemData.Featured then
436 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 end
457
458 -- Item Image
459 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 })
468
469 -- Item Name
470 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 })
482
483 -- Item Description
484 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 })
497
498 -- Price Frame
499 local priceColor = CONFIG.CurrencyTypeColors[itemData.CurrencyType or "Robux"] or CONFIG.CurrencyTypeColors.Robux
500 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})
513
514 -- Owned badge for gamepasses
515 if itemData.Type == "Gamepass" and itemData.Owned then
516 priceBtn.Visible = false
517 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 end
538
539 return {
540 Frame = card,
541 PriceButton = priceBtn,
542 Data = itemData,
543 }
544end
545
546-- ============================================
547-- LOGIC
548-- ============================================
549local Logic = {}
550
551function Logic.SetupInteractions()
552 -- Close button
553 UI.MainFrame.HeaderBar.CloseButton.MouseButton1Click:Connect(function()
554 Logic.Hide()
555 end)
556
557 -- Category tabs
558 for catId, tabData in pairs(UI.Tabs) do
559 tabData.Button.MouseButton1Click:Connect(function()
560 Logic.SetCategory(catId)
561 end)
562 end
563
564 -- Purchase prompt buttons
565 UI.BuyRobuxButton.MouseButton1Click:Connect(function()
566 Logic.ConfirmPurchase()
567 end)
568 UI.CancelPromptButton.MouseButton1Click:Connect(function()
569 Logic.HidePurchasePrompt()
570 end)
571
572 -- MarketplaceService callbacks
573 MarketplaceService.PromptGamePassPurchaseFinished:Connect(function(player, gamePassId, wasPurchased)
574 if player == Players.LocalPlayer and wasPurchased then
575 Logic.ShowToast("Gamepass purchased successfully!")
576 Logic.RefreshShop()
577 end
578 end)
579
580 MarketplaceService.PromptProductPurchaseFinished:Connect(function(userId, productId, wasPurchased)
581 if userId == Players.LocalPlayer.UserId and wasPurchased then
582 Logic.ShowToast("Purchase completed!")
583 Logic.RefreshBalances()
584 end
585 end)
586end
587
588function Logic.LoadShopData()
589 -- Demo data - in production: RequestShopData:InvokeServer()
590 State.ShopItems = {
591 -- Featured
592 {
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 -- Gamepasses
618 {
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 -- Currency
643 {
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 -- Boosts
677 {
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 -- Cosmetics
700 {
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 }
723
724 State.CoinBalance = 5000
725 State.GemBalance = 1250
726
727 Logic.RefreshBalances()
728 Logic.RefreshItemGrid()
729end
730
731function Logic.RefreshBalances()
732 UI.CoinsAmount.Text = FormatNumber(State.CoinBalance)
733 UI.GemsAmount.Text = FormatNumber(State.GemBalance)
734end
735
736function Logic.RefreshItemGrid()
737 -- Clear existing
738 for _, child in ipairs(UI.ItemGrid:GetChildren()) do
739 if child:IsA("Frame") then child:Destroy() end
740 end
741 UI.ItemCards = {}
742
743 -- Filter items
744 local filtered = {}
745 for _, item in ipairs(State.ShopItems) do
746 local show = false
747 if State.CurrentCategory == "Featured" then
748 show = item.Featured or false
749 else
750 show = item.Category == State.CurrentCategory
751 end
752 if show then
753 table.insert(filtered, item)
754 end
755 end
756
757 -- Create cards
758 for i, item in ipairs(filtered) do
759 local card = UI.CreateItemCard(item, i)
760 table.insert(UI.ItemCards, card)
761
762 -- Card hover
763 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)
771
772 -- Purchase click
773 card.PriceButton.MouseButton1Click:Connect(function()
774 Logic.OnPurchaseClick(item)
775 end)
776 end
777
778 -- Update canvas
779 local rows = math.ceil(#filtered / CONFIG.ItemsPerRow)
780 UI.ItemGrid.CanvasSize = UDim2.new(0, 0, 0, rows * 220)
781end
782
783function Logic.SetCategory(categoryId)
784 State.CurrentCategory = categoryId
785
786 -- Update tab visuals
787 for catId, tabData in pairs(UI.Tabs) do
788 local isActive = catId == categoryId
789 tabData.Button.BackgroundColor3 = isActive
790 and Color3.fromRGB(85, 90, 130) or Color3.fromRGB(60, 65, 100)
791 tabData.Button.TextColor3 = isActive
792 and Color3.fromRGB(255, 255, 255) or Color3.fromRGB(200, 200, 220)
793 end
794
795 Logic.RefreshItemGrid()
796end
797
798function Logic.OnPurchaseClick(item)
799 if item.Type == "Gamepass" and item.GamepassId then
800 -- Check if owned
801 local isOwned = State.OwnedGamepasses[item.GamepassId]
802 if isOwned then
803 Logic.ShowToast("You already own this gamepass!")
804 return
805 end
806 -- Prompt gamepass purchase
807 MarketplaceService:PromptGamePassPurchase(player, item.GamepassId)
808 elseif item.Type == "Product" and item.ProductId then
809 -- Store for confirmation
810 State.SelectedItem = item
811 Logic.ShowPurchasePrompt(item)
812 end
813end
814
815function Logic.ShowPurchasePrompt(item)
816 UI.PromptImage.Image = item.Icon or ""
817 UI.PromptName.Text = item.Name
818 UI.PromptDesc.Text = item.Description or ""
819
820 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.Robux
823
824 UI.PurchasePrompt.Visible = true
825 UI.PurchasePrompt.Size = UDim2.new(0, 320, 0, 290)
826 TweenBounce(UI.PurchasePrompt, {Size = UDim2.new(0, 360, 0, 320)}, 0.3)
827end
828
829function 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 = false
833 end)
834end
835
836function Logic.ConfirmPurchase()
837 if not State.SelectedItem then return end
838
839 local item = State.SelectedItem
840
841 if item.Type == "Product" and item.ProductId then
842 -- Prompt developer product purchase
843 MarketplaceService:PromptProductPurchase(player, item.ProductId)
844 end
845
846 Logic.HidePurchasePrompt()
847end
848
849function Logic.ShowToast(message)
850 UI.ToastText.Text = message
851 UI.ToastFrame.Visible = true
852 UI.ToastFrame.Position = UDim2.new(1, -15, 1, 80)
853
854 Tween(UI.ToastFrame, {Position = UDim2.new(1, -15, 1, -15)}, 0.3, Enum.EasingStyle.Back, Enum.EasingDirection.Out)
855
856 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 = false
860 end)
861 end)
862end
863
864function Logic.Show()
865 State.IsVisible = true
866 UI.ScreenGui.Enabled = true
867 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()
870end
871
872function Logic.Hide()
873 State.IsVisible = false
874 Tween(UI.MainFrame, {Size = UDim2.new(0, 540, 0, 400)}, 0.2)
875 task.delay(0.2, function()
876 if not State.IsVisible then
877 UI.ScreenGui.Enabled = false
878 end
879 end)
880end
881
882function Logic.Toggle()
883 if State.IsVisible then Logic.Hide() else Logic.Show() end
884end
885
886-- ============================================
887-- INITIALIZATION
888-- ============================================
889UI.Build()
890Logic.SetupInteractions()
891
892-- Bind to key
893UserInputService.InputBegan:Connect(function(input, gameProcessed)
894 if gameProcessed then return end
895 if input.KeyCode == Enum.KeyCode.B then
896 Logic.Toggle()
897 end
898end)
899
900print("Shop UI System initialized! Press 'B' to open shop.")

Code preview

Shop UI

Luau
Interactive visual preview is shown in the Live preview section above.Switch tabs to inspect the generated Luau client/server code.
Visual preview of the templateRoblox GUI Maker

Frequently asked questions

Keep going

Similar templates