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

Pet Shop Roblox GUI Template with Buy & Equip Pets

A cartoony pet shop UI with rarity badges, buy buttons, coin balance, and equipped-pet preview panel. Designed for pet collection games, simulators, and RPGs where players can browse, purchase, and equip companion pets. Features 6 pet cards with visual rarity indicators, animated purchase flow, and a dedicated preview panel for the currently equipped pet.

ShopMarketplace· Open in editor for free during beta
Pet Shop Roblox GUI template — Buy & Equip Pets, cartoon shop layout, screenshot 1
Pet Shop Roblox GUI template — screenshot 1 of 1, showing buy & equip pets on a cartoon shop layout for desktop.
Open in Web EditorChecking access…

Live preview

Pet Shop

1920×1080
Zoom100%
Desktop (FHD)
ScreenGui
Frame
🪙 1,250 Coins
Frame
Frame
Pet 1
Buy
Frame
Frame
Pet 2
Buy
Frame
Frame
Pet 3
Buy
Frame
Frame
Pet 4
Buy
Frame
Frame
Pet 5
Buy
Frame
Frame
Pet 6
Buy
A cartoony pet shop UI with rarity badges, buy buttons, coin balance, and equipped-pet preview panel. Designed for pet collection games, simulators, and RPGs where players can browse, purchase, and equip companion pets. Features 6 pet cards with visual rarity indicators, animated purchase flow, and a dedicated preview panel for the currently equipped pet.

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

What's inside

How to use this template

The Pet Shop template is built for pet collection games and simulators. Paste the client Luau into StarterGui and a shop panel appears with six pet cards, each showing a pet icon, rarity badge, and Buy button. The layout uses UIGridLayout so cards arrange in a clean grid that reflows on mobile. Clicking Buy fires a RemoteEvent to the server, which validates the purchase and grants the pet - the server Luau stub shows the validation pattern with MarketplaceService or your own currency system. The coin balance header updates in real time when the player buys. To customize, replace the placeholder pet data with your own pet IDs, icons, and prices. The rarity colors are driven by a lookup table, so adding a new rarity tier is one line. Test the purchase flow in Studio by firing the RemoteEvent manually and confirming the server responds correctly.

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.

pet-shop.lua
lua
1--[[
2 Pet Shop System - Client
3 Features: 6 pet cards with rarity badges, coin balance, buy/equip, preview panel
4 Place in: StarterPlayer > StarterPlayerScripts
5--]]
6
7local Players = game:GetService("Players")
8local TweenService = game:GetService("TweenService")
9local ReplicatedStorage = game:GetService("ReplicatedStorage")
10local MarketplaceService = game:GetService("MarketplaceService")
11
12local player = Players.LocalPlayer
13local playerGui = player:WaitForChild("PlayerGui")
14
15-- Remote Events
16local PetShopRemotes = ReplicatedStorage:WaitForChild("PetShopRemotes")
17local RequestPets = PetShopRemotes:WaitForChild("RequestPets")
18local BuyPet = PetShopRemotes:WaitForChild("BuyPet")
19local EquipPet = PetShopRemotes:WaitForChild("EquipPet")
20local UnequipPet = PetShopRemotes:WaitForChild("UnequipPet")
21local GetCoinBalance = PetShopRemotes:WaitForChild("GetCoinBalance")
22
23-- ============================================
24-- CONFIGURATION
25-- ============================================
26local CONFIG = {
27 AnimSpeed = 0.3,
28 CardHoverScale = 1.04,
29 PetsPerPage = 6,
30 RarityColors = {
31 Common = Color3.fromRGB(169, 169, 169),
32 Uncommon = Color3.fromRGB(50, 180, 50),
33 Rare = Color3.fromRGB(50, 120, 220),
34 Epic = Color3.fromRGB(148, 50, 200),
35 Legendary = Color3.fromRGB(220, 150, 30),
36 Mythic = Color3.fromRGB(220, 50, 80),
37 },
38 RarityGlows = {
39 Common = 1,
40 Uncommon = 2,
41 Rare = 3,
42 Epic = 4,
43 Legendary = 5,
44 Mythic = 6,
45 },
46}
47
48-- ============================================
49-- STATE
50-- ============================================
51local State = {
52 IsVisible = false,
53 Pets = {},
54 OwnedPets = {},
55 EquippedPet = nil,
56 SelectedPet = nil,
57 CoinBalance = 0,
58 CurrentFilter = "All",
59 PurchasePending = false,
60}
61
62-- ============================================
63-- UTILITY
64-- ============================================
65local function Create(className, properties)
66 local instance = Instance.new(className)
67 for key, value in pairs(properties or {}) do
68 instance[key] = value
69 end
70 return instance
71end
72
73local function Tween(instance, properties, duration, easingStyle, easingDirection)
74 local tween = TweenService:Create(
75 instance,
76 TweenInfo.new(
77 duration or CONFIG.AnimSpeed,
78 easingStyle or Enum.EasingStyle.Quad,
79 easingDirection or Enum.EasingDirection.Out
80 ),
81 properties
82 )
83 tween:Play()
84 return tween
85end
86
87local function FormatNumber(num)
88 if num >= 1000000 then return string.format("%.1fM", num / 1000000)
89 elseif num >= 1000 then return string.format("%.1fK", num / 1000)
90 else return tostring(num) end
91end
92
93-- ============================================
94-- UI CONSTRUCTION
95-- ============================================
96local UI = {}
97
98function UI.Build()
99 -- ScreenGui
100 local screenGui = Create("ScreenGui", {
101 Name = "PetShopGui",
102 Parent = playerGui,
103 ResetOnSpawn = false,
104 ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
105 Enabled = false,
106 })
107 UI.ScreenGui = screenGui
108
109 -- Background Dim
110 local bgDim = Create("Frame", {
111 Name = "BackgroundDim",
112 Parent = screenGui,
113 Size = UDim2.new(1, 0, 1, 0),
114 BackgroundColor3 = Color3.fromRGB(0, 0, 0),
115 BackgroundTransparency = 0.5,
116 BorderSizePixel = 0,
117 ZIndex = 1,
118 })
119
120 -- Main Frame
121 local mainFrame = Create("Frame", {
122 Name = "MainFrame",
123 Parent = screenGui,
124 AnchorPoint = Vector2.new(0.5, 0.5),
125 Position = UDim2.new(0.5, 0, 0.5, 0),
126 Size = UDim2.new(0, 650, 0, 450),
127 BackgroundColor3 = Color3.fromRGB(50, 45, 65),
128 BorderSizePixel = 0,
129 ClipsDescendants = true,
130 ZIndex = 10,
131 })
132 UI.MainFrame = mainFrame
133
134 Create("UICorner", {CornerRadius = UDim.new(0, 16), Parent = mainFrame})
135 Create("UIGradient", {
136 Color = ColorSequence.new({
137 ColorSequenceKeypoint.new(0, Color3.fromRGB(55, 50, 75)),
138 ColorSequenceKeypoint.new(1, Color3.fromRGB(42, 38, 58)),
139 }),
140 Rotation = 135,
141 Parent = mainFrame,
142 })
143
144 -- Header Frame
145 local headerFrame = Create("Frame", {
146 Name = "HeaderFrame",
147 Parent = mainFrame,
148 Size = UDim2.new(1, 0, 0, 56),
149 BackgroundColor3 = Color3.fromRGB(60, 55, 80),
150 BorderSizePixel = 0,
151 ZIndex = 11,
152 })
153
154 -- Shop Title
155 Create("TextLabel", {
156 Name = "ShopTitle",
157 Parent = headerFrame,
158 Position = UDim2.new(0, 18, 0, 0),
159 Size = UDim2.new(0, 200, 1, 0),
160 BackgroundTransparency = 1,
161 Text = "PET SHOP",
162 TextColor3 = Color3.fromRGB(255, 220, 100),
163 TextSize = 26,
164 Font = Enum.Font.GothamBlack,
165 TextXAlignment = Enum.TextXAlignment.Left,
166 ZIndex = 12,
167 })
168
169 -- Coin Display
170 local coinDisplay = Create("Frame", {
171 Name = "CoinDisplay",
172 Parent = headerFrame,
173 Position = UDim2.new(1, -160, 0.5, -17),
174 Size = UDim2.new(0, 130, 0, 34),
175 BackgroundColor3 = Color3.fromRGB(45, 40, 30),
176 BorderSizePixel = 0,
177 ZIndex = 12,
178 })
179 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = coinDisplay})
180 Create("UIStroke", {Color = Color3.fromRGB(200, 160, 50), Thickness = 1, Parent = coinDisplay})
181
182 UI.CoinAmount = Create("TextLabel", {
183 Name = "CoinAmount",
184 Parent = coinDisplay,
185 Position = UDim2.new(0, 32, 0, 0),
186 Size = UDim2.new(1, -36, 1, 0),
187 BackgroundTransparency = 1,
188 Text = "12,500",
189 TextColor3 = Color3.fromRGB(255, 200, 50),
190 TextSize = 18,
191 Font = Enum.Font.GothamBold,
192 ZIndex = 13,
193 })
194
195 -- Close Button
196 local closeButton = Create("TextButton", {
197 Name = "CloseButton",
198 Parent = headerFrame,
199 Position = UDim2.new(1, -42, 0, 10),
200 Size = UDim2.new(0, 32, 0, 32),
201 BackgroundColor3 = Color3.fromRGB(200, 60, 60),
202 Text = "X",
203 TextColor3 = Color3.fromRGB(255, 255, 255),
204 TextSize = 18,
205 Font = Enum.Font.GothamBold,
206 ZIndex = 12,
207 })
208 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = closeButton})
209
210 -- Category Tabs
211 local tabsFrame = Create("Frame", {
212 Name = "CategoryTabs",
213 Parent = mainFrame,
214 Position = UDim2.new(0, 0, 0, 56),
215 Size = UDim2.new(1, 0, 0, 38),
216 BackgroundColor3 = Color3.fromRGB(48, 43, 65),
217 BorderSizePixel = 0,
218 ZIndex = 11,
219 })
220 Create("UIListLayout", {
221 FillDirection = Enum.FillDirection.Horizontal,
222 HorizontalAlignment = Enum.HorizontalAlignment.Center,
223 VerticalAlignment = Enum.VerticalAlignment.Center,
224 Padding = UDim.new(0, 8),
225 Parent = tabsFrame,
226 })
227
228 local tabNames = {"All", "Common", "Rare", "Legendary"}
229 UI.Tabs = {}
230 for _, tabName in ipairs(tabNames) do
231 local tabBtn = Create("TextButton", {
232 Name = tabName .. "Tab",
233 Parent = tabsFrame,
234 Size = UDim2.new(0, 90, 0, 30),
235 BackgroundColor3 = tabName == "All" and Color3.fromRGB(80, 70, 110) or Color3.fromRGB(55, 50, 75),
236 Text = tabName,
237 TextColor3 = Color3.fromRGB(220, 215, 240),
238 TextSize = 14,
239 Font = Enum.Font.GothamBold,
240 ZIndex = 12,
241 })
242 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = tabBtn})
243 UI.Tabs[tabName] = tabBtn
244 end
245
246 -- Content Area
247 local contentArea = Create("Frame", {
248 Name = "ContentArea",
249 Parent = mainFrame,
250 Position = UDim2.new(0, 0, 0, 94),
251 Size = UDim2.new(1, 0, 1, -94),
252 BackgroundTransparency = 1,
253 ZIndex = 11,
254 })
255
256 -- Pet Grid (Left side)
257 local petGrid = Create("ScrollingFrame", {
258 Name = "PetGrid",
259 Parent = contentArea,
260 Position = UDim2.new(0, 10, 0, 0),
261 Size = UDim2.new(0, 405, 1, -10),
262 BackgroundTransparency = 1,
263 ScrollBarThickness = 6,
264 ScrollBarImageColor3 = Color3.fromRGB(80, 75, 100),
265 CanvasSize = UDim2.new(0, 0, 0, 0),
266 ZIndex = 12,
267 })
268 UI.PetGrid = petGrid
269
270 Create("UIGridLayout", {
271 CellSize = UDim2.new(0, 190, 0, 210),
272 CellPadding = UDim2.new(0, 12, 0, 12),
273 SortOrder = Enum.SortOrder.Name,
274 Parent = petGrid,
275 })
276
277 -- Preview Panel (Right side)
278 local previewPanel = Create("Frame", {
279 Name = "PreviewPanel",
280 Parent = contentArea,
281 Position = UDim2.new(0, 420, 0, 5),
282 Size = UDim2.new(0, 215, 1, -15),
283 BackgroundColor3 = Color3.fromRGB(45, 42, 60),
284 BorderSizePixel = 0,
285 ZIndex = 12,
286 })
287 Create("UICorner", {CornerRadius = UDim.new(0, 12), Parent = previewPanel})
288
289 -- Panel Title
290 Create("TextLabel", {
291 Name = "PanelTitle",
292 Parent = previewPanel,
293 Position = UDim2.new(0, 0, 0, 8),
294 Size = UDim2.new(1, 0, 0, 26),
295 BackgroundTransparency = 1,
296 Text = "YOUR PET",
297 TextColor3 = Color3.fromRGB(200, 190, 230),
298 TextSize = 16,
299 Font = Enum.Font.GothamBold,
300 ZIndex = 13,
301 })
302
303 -- Preview Image Frame
304 local previewImageFrame = Create("Frame", {
305 Name = "PreviewImageFrame",
306 Parent = previewPanel,
307 Position = UDim2.new(0.5, -80, 0, 38),
308 Size = UDim2.new(0, 160, 0, 160),
309 BackgroundColor3 = Color3.fromRGB(55, 52, 72),
310 BorderSizePixel = 0,
311 ZIndex = 13,
312 })
313 Create("UICorner", {CornerRadius = UDim.new(0, 12), Parent = previewImageFrame})
314 UI.PreviewImage = Create("ImageLabel", {
315 Name = "PreviewImage",
316 Parent = previewImageFrame,
317 Size = UDim2.new(1, -12, 1, -12),
318 Position = UDim2.new(0, 6, 0, 6),
319 BackgroundTransparency = 1,
320 Image = "",
321 ZIndex = 14,
322 })
323
324 -- Equipped Badge
325 UI.EquippedBadge = Create("Frame", {
326 Name = "EquippedBadge",
327 Parent = previewImageFrame,
328 Position = UDim2.new(0, 6, 0, 6),
329 Size = UDim2.new(0, 70, 0, 22),
330 BackgroundColor3 = Color3.fromRGB(50, 180, 80),
331 BorderSizePixel = 0,
332 Visible = false,
333 ZIndex = 15,
334 })
335 Create("UICorner", {CornerRadius = UDim.new(0, 6), Parent = UI.EquippedBadge})
336 Create("TextLabel", {
337 Parent = UI.EquippedBadge,
338 Size = UDim2.new(1, 0, 1, 0),
339 BackgroundTransparency = 1,
340 Text = "EQUIPPED",
341 TextColor3 = Color3.fromRGB(255, 255, 255),
342 TextSize = 11,
343 Font = Enum.Font.GothamBold,
344 ZIndex = 16,
345 })
346
347 -- Equipped Name
348 UI.EquippedName = Create("TextLabel", {
349 Name = "EquippedName",
350 Parent = previewPanel,
351 Position = UDim2.new(0, 0, 0, 205),
352 Size = UDim2.new(1, 0, 0, 22),
353 BackgroundTransparency = 1,
354 Text = "No Pet Equipped",
355 TextColor3 = Color3.fromRGB(200, 200, 220),
356 TextSize = 16,
357 Font = Enum.Font.GothamBold,
358 ZIndex = 13,
359 })
360
361 -- Equipped Rarity
362 UI.EquippedRarity = Create("TextLabel", {
363 Name = "EquippedRarity",
364 Parent = previewPanel,
365 Position = UDim2.new(0, 0, 0, 228),
366 Size = UDim2.new(1, 0, 0, 18),
367 BackgroundTransparency = 1,
368 Text = "Select a pet",
369 TextColor3 = Color3.fromRGB(160, 160, 180),
370 TextSize = 13,
371 Font = Enum.Font.GothamSemibold,
372 ZIndex = 13,
373 })
374
375 -- Equipped Stats Bars
376 local statsFrame = Create("Frame", {
377 Name = "EquippedStats",
378 Parent = previewPanel,
379 Position = UDim2.new(0, 12, 0, 255),
380 Size = UDim2.new(1, -24, 0, 100),
381 BackgroundTransparency = 1,
382 ZIndex = 13,
383 })
384
385 local statNames = {"Speed", "Power", "Luck"}
386 local statColors = {
387 Speed = Color3.fromRGB(50, 180, 220),
388 Power = Color3.fromRGB(220, 80, 60),
389 Luck = Color3.fromRGB(180, 220, 60),
390 }
391 UI.StatBars = {}
392 for i, statName in ipairs(statNames) do
393 local yPos = (i - 1) * 32
394 Create("TextLabel", {
395 Parent = statsFrame,
396 Position = UDim2.new(0, 0, 0, yPos),
397 Size = UDim2.new(0, 55, 0, 18),
398 BackgroundTransparency = 1,
399 Text = statName,
400 TextColor3 = Color3.fromRGB(180, 175, 200),
401 TextSize = 12,
402 Font = Enum.Font.GothamSemibold,
403 TextXAlignment = Enum.TextXAlignment.Left,
404 ZIndex = 14,
405 })
406 local barBg = Create("Frame", {
407 Parent = statsFrame,
408 Position = UDim2.new(0, 58, 0, yPos + 2),
409 Size = UDim2.new(1, -60, 0, 14),
410 BackgroundColor3 = Color3.fromRGB(35, 32, 48),
411 BorderSizePixel = 0,
412 ZIndex = 14,
413 })
414 Create("UICorner", {CornerRadius = UDim.new(0, 7), Parent = barBg})
415 local barFill = Create("Frame", {
416 Parent = barBg,
417 Size = UDim2.new(0, 0, 1, 0),
418 BackgroundColor3 = statColors[statName],
419 BorderSizePixel = 0,
420 ZIndex = 15,
421 })
422 Create("UICorner", {CornerRadius = UDim.new(0, 7), Parent = barFill})
423 UI.StatBars[statName] = barFill
424 end
425
426 -- Equip Action Button
427 UI.EquipButton = Create("TextButton", {
428 Name = "EquipActionButton",
429 Parent = previewPanel,
430 Position = UDim2.new(0.5, -80, 1, -48),
431 Size = UDim2.new(0, 160, 0, 38),
432 BackgroundColor3 = Color3.fromRGB(50, 160, 70),
433 Text = "EQUIP",
434 TextColor3 = Color3.fromRGB(255, 255, 255),
435 TextSize = 16,
436 Font = Enum.Font.GothamBold,
437 Visible = false,
438 ZIndex = 13,
439 })
440 Create("UICorner", {CornerRadius = UDim.new(0, 10), Parent = UI.EquipButton})
441
442 -- Unequip Action Button
443 UI.UnequipButton = Create("TextButton", {
444 Name = "UnequipActionButton",
445 Parent = previewPanel,
446 Position = UDim2.new(0.5, -80, 1, -48),
447 Size = UDim2.new(0, 160, 0, 38),
448 BackgroundColor3 = Color3.fromRGB(160, 80, 50),
449 Text = "UNEQUIP",
450 TextColor3 = Color3.fromRGB(255, 255, 255),
451 TextSize = 16,
452 Font = Enum.Font.GothamBold,
453 Visible = false,
454 ZIndex = 13,
455 })
456 Create("UICorner", {CornerRadius = UDim.new(0, 10), Parent = UI.UnequipButton})
457
458 -- Purchase Modal
459 local purchaseModal = Create("Frame", {
460 Name = "PurchaseModal",
461 Parent = screenGui,
462 AnchorPoint = Vector2.new(0.5, 0.5),
463 Position = UDim2.new(0.5, 0, 0.5, 0),
464 Size = UDim2.new(0, 340, 0, 280),
465 BackgroundColor3 = Color3.fromRGB(45, 42, 62),
466 BorderSizePixel = 0,
467 Visible = false,
468 ZIndex = 200,
469 })
470 UI.PurchaseModal = purchaseModal
471 Create("UICorner", {CornerRadius = UDim.new(0, 16), Parent = purchaseModal})
472 Create("UIStroke", {Color = Color3.fromRGB(200, 170, 60), Thickness = 2, Parent = purchaseModal})
473
474 Create("TextLabel", {
475 Name = "ModalTitle",
476 Parent = purchaseModal,
477 Position = UDim2.new(0, 0, 0, 12),
478 Size = UDim2.new(1, 0, 0, 30),
479 BackgroundTransparency = 1,
480 Text = "CONFIRM PURCHASE",
481 TextColor3 = Color3.fromRGB(255, 220, 100),
482 TextSize = 20,
483 Font = Enum.Font.GothamBlack,
484 ZIndex = 201,
485 })
486 UI.ModalPetImage = Create("ImageLabel", {
487 Name = "ModalPetImage",
488 Parent = purchaseModal,
489 Position = UDim2.new(0.5, -50, 0, 48),
490 Size = UDim2.new(0, 100, 0, 100),
491 BackgroundTransparency = 1,
492 Image = "",
493 ZIndex = 201,
494 })
495 UI.ModalPetName = Create("TextLabel", {
496 Name = "ModalPetName",
497 Parent = purchaseModal,
498 Position = UDim2.new(0, 0, 0, 152),
499 Size = UDim2.new(1, 0, 0, 24),
500 BackgroundTransparency = 1,
501 Text = "Pet Name",
502 TextColor3 = Color3.fromRGB(255, 255, 255),
503 TextSize = 18,
504 Font = Enum.Font.GothamBold,
505 ZIndex = 201,
506 })
507 UI.ModalPrice = Create("TextLabel", {
508 Name = "ModalPrice",
509 Parent = purchaseModal,
510 Position = UDim2.new(0, 0, 0, 178),
511 Size = UDim2.new(1, 0, 0, 22),
512 BackgroundTransparency = 1,
513 Text = "2,500 Coins",
514 TextColor3 = Color3.fromRGB(255, 200, 50),
515 TextSize = 16,
516 Font = Enum.Font.GothamBold,
517 ZIndex = 201,
518 })
519 local confirmBtn = Create("TextButton", {
520 Name = "ConfirmButton",
521 Parent = purchaseModal,
522 Position = UDim2.new(0, 20, 0, 215),
523 Size = UDim2.new(0, 135, 0, 40),
524 BackgroundColor3 = Color3.fromRGB(50, 180, 80),
525 Text = "BUY",
526 TextColor3 = Color3.fromRGB(255, 255, 255),
527 TextSize = 18,
528 Font = Enum.Font.GothamBlack,
529 ZIndex = 201,
530 })
531 Create("UICorner", {CornerRadius = UDim.new(0, 10), Parent = confirmBtn})
532 UI.ConfirmPurchaseButton = confirmBtn
533
534 local cancelBtn = Create("TextButton", {
535 Name = "CancelButton",
536 Parent = purchaseModal,
537 Position = UDim2.new(0, 185, 0, 215),
538 Size = UDim2.new(0, 135, 0, 40),
539 BackgroundColor3 = Color3.fromRGB(160, 60, 60),
540 Text = "CANCEL",
541 TextColor3 = Color3.fromRGB(255, 255, 255),
542 TextSize = 18,
543 Font = Enum.Font.GothamBlack,
544 ZIndex = 201,
545 })
546 Create("UICorner", {CornerRadius = UDim.new(0, 10), Parent = cancelBtn})
547 UI.CancelPurchaseButton = cancelBtn
548
549 -- Notification Frame
550 UI.NotificationFrame = Create("Frame", {
551 Name = "NotificationFrame",
552 Parent = screenGui,
553 AnchorPoint = Vector2.new(0.5, 0),
554 Position = UDim2.new(0.5, 0, 0, -60),
555 Size = UDim2.new(0, 300, 0, 44),
556 BackgroundColor3 = Color3.fromRGB(50, 45, 65),
557 BorderSizePixel = 0,
558 Visible = false,
559 ZIndex = 500,
560 })
561 Create("UICorner", {CornerRadius = UDim.new(0, 10), Parent = UI.NotificationFrame})
562 Create("UIStroke", {Color = Color3.fromRGB(80, 180, 80), Thickness = 2, Parent = UI.NotificationFrame})
563 UI.NotificationText = Create("TextLabel", {
564 Name = "NotificationText",
565 Parent = UI.NotificationFrame,
566 Size = UDim2.new(1, 0, 1, 0),
567 BackgroundTransparency = 1,
568 Text = "Purchase successful!",
569 TextColor3 = Color3.fromRGB(255, 255, 255),
570 TextSize = 15,
571 Font = Enum.Font.GothamBold,
572 ZIndex = 501,
573 })
574
575 return UI
576end
577
578-- ============================================
579-- PET CARD CREATION
580-- ============================================
581function UI.CreatePetCard(petData, index)
582 local rarityColor = CONFIG.RarityColors[petData.Rarity] or CONFIG.RarityColors.Common
583 local card = Create("Frame", {
584 Name = "PetCard_" .. string.format("%02d", index),
585 Parent = UI.PetGrid,
586 Size = UDim2.new(0, 190, 0, 210),
587 BackgroundColor3 = Color3.fromRGB(52, 48, 70),
588 BorderSizePixel = 0,
589 ZIndex = 13,
590 })
591 Create("UICorner", {CornerRadius = UDim.new(0, 12), Parent = card})
592 local stroke = Create("UIStroke", {
593 Color = rarityColor,
594 Thickness = 2,
595 Parent = card,
596 })
597
598 -- Pet Image
599 local petImage = Create("ImageLabel", {
600 Name = "PetImage",
601 Parent = card,
602 Position = UDim2.new(0.5, -60, 0, 8),
603 Size = UDim2.new(0, 120, 0, 100),
604 BackgroundTransparency = 1,
605 Image = petData.Icon or "",
606 ZIndex = 14,
607 })
608
609 -- Rarity Badge
610 local badge = Create("Frame", {
611 Name = "RarityBadge",
612 Parent = card,
613 Position = UDim2.new(0, 6, 0, 6),
614 Size = UDim2.new(0, 70, 0, 20),
615 BackgroundColor3 = rarityColor,
616 BorderSizePixel = 0,
617 ZIndex = 15,
618 })
619 Create("UICorner", {CornerRadius = UDim.new(0, 6), Parent = badge})
620 Create("TextLabel", {
621 Parent = badge,
622 Size = UDim2.new(1, 0, 1, 0),
623 BackgroundTransparency = 1,
624 Text = string.upper(petData.Rarity or "Common"),
625 TextColor3 = Color3.fromRGB(255, 255, 255),
626 TextSize = 10,
627 Font = Enum.Font.GothamBold,
628 ZIndex = 16,
629 })
630
631 -- Pet Name
632 Create("TextLabel", {
633 Name = "PetName",
634 Parent = card,
635 Position = UDim2.new(0, 0, 0, 114),
636 Size = UDim2.new(1, 0, 0, 22),
637 BackgroundTransparency = 1,
638 Text = petData.Name or "Unknown",
639 TextColor3 = Color3.fromRGB(240, 235, 255),
640 TextSize = 15,
641 Font = Enum.Font.GothamBold,
642 ZIndex = 14,
643 })
644
645 -- Pet Stats
646 Create("TextLabel", {
647 Name = "PetStats",
648 Parent = card,
649 Position = UDim2.new(0, 0, 0, 136),
650 Size = UDim2.new(1, 0, 0, 16),
651 BackgroundTransparency = 1,
652 Text = string.format("SPD: %d | PWR: %d", petData.Stats.Speed, petData.Stats.Power),
653 TextColor3 = Color3.fromRGB(160, 155, 180),
654 TextSize = 11,
655 Font = Enum.Font.Gotham,
656 ZIndex = 14,
657 })
658
659 -- Price / Owned Button
660 local priceBtn = Create("TextButton", {
661 Name = "PriceButton",
662 Parent = card,
663 Position = UDim2.new(0.5, -70, 0, 160),
664 Size = UDim2.new(0, 140, 0, 36),
665 BackgroundColor3 = Color3.fromRGB(55, 130, 70),
666 Text = " " .. FormatNumber(petData.Price),
667 TextColor3 = Color3.fromRGB(255, 255, 255),
668 TextSize = 15,
669 Font = Enum.Font.GothamBold,
670 ZIndex = 14,
671 })
672 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = priceBtn})
673
674 return {
675 Frame = card,
676 Stroke = stroke,
677 PetImage = petImage,
678 PriceButton = priceBtn,
679 Data = petData,
680 }
681end
682
683-- ============================================
684-- LOGIC
685-- ============================================
686local Logic = {}
687
688function Logic.SetupInteractions()
689 -- Close button
690 UI.MainFrame.HeaderFrame.CloseButton.MouseButton1Click:Connect(function()
691 Logic.Hide()
692 end)
693
694 -- Tab filtering
695 for tabName, tabBtn in pairs(UI.Tabs) do
696 tabBtn.MouseButton1Click:Connect(function()
697 Logic.SetFilter(tabName)
698 end)
699 end
700
701 -- Purchase buttons
702 UI.ConfirmPurchaseButton.MouseButton1Click:Connect(function()
703 Logic.ConfirmPurchase()
704 end)
705 UI.CancelPurchaseButton.MouseButton1Click:Connect(function()
706 Logic.HidePurchaseModal()
707 end)
708
709 -- Equip / Unequip
710 UI.EquipButton.MouseButton1Click:Connect(function()
711 if State.SelectedPet then
712 Logic.EquipPet(State.SelectedPet.Id)
713 end
714 end)
715 UI.UnequipButton.MouseButton1Click:Connect(function()
716 Logic.UnequipPet()
717 end)
718end
719
720function Logic.LoadPets()
721 -- In production: local pets = RequestPets:InvokeServer()
722 -- Demo data
723 State.Pets = {
724 {
725 Id = "pet_dragon",
726 Name = "Fire Dragon",
727 Rarity = "Legendary",
728 Icon = "rbxassetid://12345",
729 Price = 5000,
730 Stats = {Speed = 85, Power = 95, Luck = 70},
731 Description = "A mighty fire-breathing dragon.",
732 },
733 {
734 Id = "pet_phoenix",
735 Name = "Phoenix",
736 Rarity = "Legendary",
737 Icon = "rbxassetid://12346",
738 Price = 4500,
739 Stats = {Speed = 90, Power = 80, Luck = 85},
740 Description = "Rises from the ashes.",
741 },
742 {
743 Id = "pet_wolf",
744 Name = "Shadow Wolf",
745 Rarity = "Rare",
746 Icon = "rbxassetid://12347",
747 Price = 2500,
748 Stats = {Speed = 92, Power = 65, Luck = 60},
749 Description = "A loyal shadow companion.",
750 },
751 {
752 Id = "pet_cat",
753 Name = "Lucky Cat",
754 Rarity = "Uncommon",
755 Icon = "rbxassetid://12348",
756 Price = 1000,
757 Stats = {Speed = 60, Power = 40, Luck = 95},
758 Description = "Brings good fortune.",
759 },
760 {
761 Id = "pet_dog",
762 Name = "Golden Retriever",
763 Rarity = "Common",
764 Icon = "rbxassetid://12349",
765 Price = 500,
766 Stats = {Speed = 70, Power = 50, Luck = 65},
767 Description = "A faithful friend.",
768 },
769 {
770 Id = "pet_unicorn",
771 Name = "Rainbow Unicorn",
772 Rarity = "Epic",
773 Icon = "rbxassetid://12350",
774 Price = 3500,
775 Stats = {Speed = 80, Power = 70, Luck = 90},
776 Description = "Sparkles with magic.",
777 },
778 }
779
780 State.OwnedPets = {
781 pet_dog = true, -- Demo: player owns the dog
782 }
783 State.EquippedPet = "pet_dog"
784
785 Logic.RefreshPetGrid()
786 Logic.RefreshPreview()
787end
788
789function Logic.RefreshPetGrid()
790 -- Clear existing cards
791 for _, child in ipairs(UI.PetGrid:GetChildren()) do
792 if child:IsA("Frame") then child:Destroy() end
793 end
794 UI.PetCards = {}
795
796 -- Create cards based on filter
797 local index = 0
798 for _, pet in ipairs(State.Pets) do
799 if State.CurrentFilter == "All" or pet.Rarity == State.CurrentFilter then
800 index = index + 1
801 local card = UI.CreatePetCard(pet, index)
802 table.insert(UI.PetCards, card)
803
804 -- Setup card interactions
805 card.Frame.MouseEnter:Connect(function()
806 Tween(card.Frame, {Size = UDim2.new(0, 190 * CONFIG.CardHoverScale, 0, 210 * CONFIG.CardHoverScale)}, 0.15)
807 card.Stroke.Thickness = 3 + (CONFIG.RarityGlows[pet.Rarity] or 1)
808 end)
809 card.Frame.MouseLeave:Connect(function()
810 Tween(card.Frame, {Size = UDim2.new(0, 190, 0, 210)}, 0.15)
811 card.Stroke.Thickness = 2
812 end)
813
814 card.PriceButton.MouseButton1Click:Connect(function()
815 Logic.OnPriceButtonClick(pet)
816 end)
817
818 card.Frame.InputBegan:Connect(function(input)
819 if input.UserInputType == Enum.UserInputType.MouseButton1 or
820 input.UserInputType == Enum.UserInputType.Touch then
821 Logic.SelectPet(pet)
822 end
823 end)
824 end
825 end
826
827 -- Update canvas size
828 local rows = math.ceil(index / 2)
829 UI.PetGrid.CanvasSize = UDim2.new(0, 0, 0, rows * 222)
830end
831
832function Logic.OnPriceButtonClick(pet)
833 local isOwned = State.OwnedPets[pet.Id]
834 if isOwned then
835 -- If owned, select and equip
836 Logic.SelectPet(pet)
837 Logic.EquipPet(pet.Id)
838 else
839 -- If not owned, show purchase modal
840 Logic.ShowPurchaseModal(pet)
841 end
842end
843
844function Logic.SelectPet(pet)
845 State.SelectedPet = pet
846 Logic.RefreshPreview()
847end
848
849function Logic.RefreshPreview()
850 local pet = State.SelectedPet
851 if not pet then
852 -- Show equipped pet or empty state
853 if State.EquippedPet then
854 for _, p in ipairs(State.Pets) do
855 if p.Id == State.EquippedPet then
856 pet = p
857 break
858 end
859 end
860 end
861 end
862
863 if pet then
864 UI.PreviewImage.Image = pet.Icon or ""
865 UI.EquippedName.Text = pet.Name
866 UI.EquippedName.TextColor3 = CONFIG.RarityColors[pet.Rarity] or Color3.fromRGB(255, 255, 255)
867 UI.EquippedRarity.Text = pet.Rarity
868 UI.EquippedRarity.TextColor3 = CONFIG.RarityColors[pet.Rarity] or Color3.fromRGB(200, 200, 200)
869
870 -- Update stat bars with animation
871 local maxStat = 100
872 Tween(UI.StatBars.Speed, {Size = UDim2.new(math.clamp(pet.Stats.Speed / maxStat, 0, 1), 0, 1, 0)}, 0.4)
873 Tween(UI.StatBars.Power, {Size = UDim2.new(math.clamp(pet.Stats.Power / maxStat, 0, 1), 0, 1, 0)}, 0.4)
874 Tween(UI.StatBars.Luck, {Size = UDim2.new(math.clamp(pet.Stats.Luck / maxStat, 0, 1), 0, 1, 0)}, 0.4)
875
876 -- Show equipped badge
877 local isEquipped = State.EquippedPet == pet.Id
878 UI.EquippedBadge.Visible = isEquipped
879 UI.EquippedBadge.BackgroundColor3 = CONFIG.RarityColors[pet.Rarity]
880
881 -- Show/hide equip/unequip buttons
882 local isOwned = State.OwnedPets[pet.Id]
883 if isEquipped then
884 UI.EquipButton.Visible = false
885 UI.UnequipButton.Visible = true
886 elseif isOwned then
887 UI.EquipButton.Visible = true
888 UI.UnequipButton.Visible = false
889 else
890 UI.EquipButton.Visible = false
891 UI.UnequipButton.Visible = false
892 end
893 else
894 UI.PreviewImage.Image = ""
895 UI.EquippedName.Text = "No Pet Equipped"
896 UI.EquippedName.TextColor3 = Color3.fromRGB(200, 200, 220)
897 UI.EquippedRarity.Text = "Select a pet"
898 UI.EquippedBadge.Visible = false
899 UI.EquipButton.Visible = false
900 UI.UnequipButton.Visible = false
901 Tween(UI.StatBars.Speed, {Size = UDim2.new(0, 0, 1, 0)}, 0.3)
902 Tween(UI.StatBars.Power, {Size = UDim2.new(0, 0, 1, 0)}, 0.3)
903 Tween(UI.StatBars.Luck, {Size = UDim2.new(0, 0, 1, 0)}, 0.3)
904 end
905end
906
907function Logic.SetFilter(filter)
908 State.CurrentFilter = filter
909
910 -- Update tab visuals
911 for tabName, tabBtn in pairs(UI.Tabs) do
912 tabBtn.BackgroundColor3 = tabName == filter
913 and Color3.fromRGB(80, 70, 110)
914 or Color3.fromRGB(55, 50, 75)
915 end
916
917 Logic.RefreshPetGrid()
918end
919
920function Logic.ShowPurchaseModal(pet)
921 if State.PurchasePending then return end
922
923 UI.ModalPetImage.Image = pet.Icon or ""
924 UI.ModalPetName.Text = pet.Name
925 UI.ModalPetName.TextColor3 = CONFIG.RarityColors[pet.Rarity]
926 UI.ModalPrice.Text = FormatNumber(pet.Price) .. " Coins"
927
928 UI.PurchaseModal.Visible = true
929 UI.PurchaseModal.Size = UDim2.new(0, 300, 0, 250)
930 Tween(UI.PurchaseModal, {Size = UDim2.new(0, 340, 0, 280)}, 0.25, Enum.EasingStyle.Back, Enum.EasingDirection.Out)
931end
932
933function Logic.HidePurchaseModal()
934 Tween(UI.PurchaseModal, {Size = UDim2.new(0, 300, 0, 250)}, 0.2)
935 task.delay(0.2, function()
936 UI.PurchaseModal.Visible = false
937 end)
938end
939
940function Logic.ConfirmPurchase()
941 if State.PurchasePending then return end
942 if not State.SelectedPet then return end
943
944 State.PurchasePending = true
945 UI.ConfirmPurchaseButton.Text = "Buying..."
946 UI.ConfirmPurchaseButton.BackgroundColor3 = Color3.fromRGB(100, 100, 100)
947
948 -- Fire server
949 local result = BuyPet:InvokeServer(State.SelectedPet.Id)
950
951 if result.Success then
952 State.OwnedPets[State.SelectedPet.Id] = true
953 State.CoinBalance = result.NewBalance or State.CoinBalance
954 UI.CoinAmount.Text = FormatNumber(State.CoinBalance)
955
956 Logic.ShowNotification("Purchase successful! You got " .. State.SelectedPet.Name)
957 Logic.RefreshPetGrid()
958
959 -- Auto-equip
960 Logic.EquipPet(State.SelectedPet.Id)
961 else
962 Logic.ShowNotification(result.Message or "Purchase failed!")
963 end
964
965 UI.ConfirmPurchaseButton.Text = "BUY"
966 UI.ConfirmPurchaseButton.BackgroundColor3 = Color3.fromRGB(50, 180, 80)
967 State.PurchasePending = false
968 Logic.HidePurchaseModal()
969end
970
971function Logic.EquipPet(petId)
972 local result = EquipPet:InvokeServer(petId)
973 if result.Success then
974 State.EquippedPet = petId
975 Logic.RefreshPreview()
976 Logic.RefreshPetGrid()
977 Logic.ShowNotification("Pet equipped!")
978 end
979end
980
981function Logic.UnequipPet()
982 local result = UnequipPet:InvokeServer()
983 if result.Success then
984 State.EquippedPet = nil
985 Logic.RefreshPreview()
986 Logic.ShowNotification("Pet unequipped!")
987 end
988end
989
990function Logic.ShowNotification(message)
991 UI.NotificationText.Text = message
992 UI.NotificationFrame.Visible = true
993 UI.NotificationFrame.Position = UDim2.new(0.5, 0, 0, -60)
994 Tween(UI.NotificationFrame, {Position = UDim2.new(0.5, 0, 0, 20)}, 0.3, Enum.EasingStyle.Back, Enum.EasingDirection.Out)
995
996 task.delay(2.5, function()
997 Tween(UI.NotificationFrame, {Position = UDim2.new(0.5, 0, 0, -60)}, 0.3)
998 task.delay(0.3, function()
999 UI.NotificationFrame.Visible = false
1000 end)
1001 end)
1002end
1003
1004function Logic.Show()
1005 State.IsVisible = true
1006 UI.ScreenGui.Enabled = true
1007 UI.MainFrame.Size = UDim2.new(0, 580, 0, 400)
1008 Tween(UI.MainFrame, {Size = UDim2.new(0, 650, 0, 450)}, 0.3, Enum.EasingStyle.Back, Enum.EasingDirection.Out)
1009 Logic.LoadPets()
1010end
1011
1012function Logic.Hide()
1013 State.IsVisible = false
1014 Tween(UI.MainFrame, {Size = UDim2.new(0, 580, 0, 400)}, 0.2)
1015 task.delay(0.2, function()
1016 if not State.IsVisible then
1017 UI.ScreenGui.Enabled = false
1018 end
1019 end)
1020end
1021
1022-- ============================================
1023-- INITIALIZATION
1024-- ============================================
1025UI.Build()
1026Logic.SetupInteractions()
1027
1028-- Show the shop immediately for demo
1029Logic.Show()
1030
1031-- Or bind to a key/button:
1032-- local function onInputBegan(input, gameProcessed)
1033-- if gameProcessed then return end
1034-- if input.KeyCode == Enum.KeyCode.P then Logic.Toggle() end
1035-- end
1036-- UserInputService.InputBegan:Connect(onInputBegan)
1037
1038print("Pet Shop System initialized!")

Code preview

Pet Shop

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