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

RPG Inventory Roblox GUI Template with Drag & Equip

A slot-based RPG inventory GUI for Roblox with drag-and-drop, equip slots, item rarity colors, and tooltips. This template provides a complete inventory system that supports item collection, equipment management, drag-and-drop interactions, rarity-based color coding, and informative tooltips on hover. It is designed for RPG, adventure, and survival games where players collect and manage items.

InventoryFree
RPG Inventory Roblox GUI template — Drag & Equip, dark inventory layout, screenshot 1
RPG Inventory Roblox GUI template — screenshot 1 of 1, showing drag & equip on a dark inventory layout for desktop.
Open in Web EditorJoin Studio plugin waitlist

Live preview

RPG Inventory

1920×1080
Zoom100%
Desktop (FHD)
ScreenGui
Frame
Inventory
Frame
Frame
Frame
Frame
Frame
Frame
Frame
Frame
Frame
Frame
Frame
Frame
Frame
Frame
Frame
Equip
A slot-based RPG inventory GUI for Roblox with drag-and-drop, equip slots, item rarity colors, and tooltips. This template provides a complete inventory system that supports item collection, equipment management, drag-and-drop interactions, rarity-based color coding, and informative tooltips on hover. It is designed for RPG, adventure, and survival games where players collect and manage items.

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

What's inside

How to use this template

The RPG Inventory template drops into any game that needs item management. Paste the client Luau into a LocalScript under StarterGui and the inventory panel appears on screen, toggled by the Tab key. The layout uses a slot-based grid with UIGridLayout, so adding or removing item slots is a matter of changing the cell count. Each slot supports drag-and-drop via UIDragDetector, and item rarity is shown by a colored UIStroke border. To wire it to your game, replace the placeholder item table with your own item data and fire a RemoteEvent to the server when the player equips or drops an item. The server Luau stub shows how to validate equip requests and persist the inventory with DataStore. Test on mobile by switching to the phone preview in the editor - the slots reflow to fit the narrower screen because the layout uses Scale-based sizing.

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.

rpg-inventory.lua
lua
1--[[
2 RPG Inventory System - Client
3 Features: Drag-and-drop, equip slots, rarity colors, tooltips
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 RunService = game:GetService("RunService")
12
13local player = Players.LocalPlayer
14local playerGui = player:WaitForChild("PlayerGui")
15
16-- Remote Events (create these in ReplicatedStorage)
17local Remotes = ReplicatedStorage:WaitForChild("InventoryRemotes")
18local RequestInventory = Remotes:WaitForChild("RequestInventory")
19local EquipItem = Remotes:WaitForChild("EquipItem")
20local UnequipItem = Remotes:WaitForChild("UnequipItem")
21local UseItem = Remotes:WaitForChild("UseItem")
22local DropItem = Remotes:WaitForChild("DropItem")
23local DestroyItem = Remotes:WaitForChild("DestroyItem")
24
25-- ============================================
26-- CONFIGURATION
27-- ============================================
28local CONFIG = {
29 InventoryRows = 5,
30 InventoryCols = 8,
31 SlotSize = 64,
32 SlotPadding = 8,
33 AnimSpeed = 0.25,
34 DoubleClickThreshold = 0.3,
35 DragThreshold = 5,
36}
37
38local RARITY_COLORS = {
39 Common = Color3.fromRGB(169, 169, 169), -- Gray
40 Uncommon = Color3.fromRGB(30, 180, 30), -- Green
41 Rare = Color3.fromRGB(30, 100, 220), -- Blue
42 Epic = Color3.fromRGB(148, 30, 180), -- Purple
43 Legendary = Color3.fromRGB(220, 150, 30), -- Orange
44 Mythic = Color3.fromRGB(220, 50, 50), -- Red
45}
46
47local RARITY_GLOWS = {
48 Common = 0,
49 Uncommon = 2,
50 Rare = 3,
51 Epic = 4,
52 Legendary = 5,
53 Mythic = 6,
54}
55
56local EQUIPMENT_SLOTS = {
57 Helmet = {Position = UDim2.new(0.5, -32, 0, 10), Label = "Helmet"},
58 Armor = {Position = UDim2.new(0.5, -32, 0, 90), Label = "Armor"},
59 Weapon = {Position = UDim2.new(0.5, -32, 0, 170), Label = "Weapon"},
60 Boots = {Position = UDim2.new(0.5, -32, 0, 250), Label = "Boots"},
61}
62
63-- ============================================
64-- STATE MANAGEMENT
65-- ============================================
66local State = {
67 Inventory = {}, -- Array of item data or nil
68 Equipped = {}, -- Map of slotType -> itemData
69 IsVisible = false,
70 Dragging = nil, -- {SlotIndex, ItemData, Ghost}
71 HoverSlot = nil,
72 LastClickTime = 0,
73 LastClickedSlot = nil,
74 TooltipVisible = false,
75 ActionMenuVisible = false,
76}
77
78-- ============================================
79-- UTILITY FUNCTIONS
80-- ============================================
81local function Create(className, properties)
82 local instance = Instance.new(className)
83 for key, value in pairs(properties or {}) do
84 instance[key] = value
85 end
86 return instance
87end
88
89local function Tween(instance, properties, duration, easingStyle, easingDirection)
90 local tween = TweenService:Create(
91 instance,
92 TweenInfo.new(
93 duration or CONFIG.AnimSpeed,
94 easingStyle or Enum.EasingStyle.Quad,
95 easingDirection or Enum.EasingDirection.Out
96 ),
97 properties
98 )
99 tween:Play()
100 return tween
101end
102
103local function FormatNumber(num)
104 if num >= 1000000 then
105 return string.format("%.1fM", num / 1000000)
106 elseif num >= 1000 then
107 return string.format("%.1fK", num / 1000)
108 else
109 return tostring(num)
110 end
111end
112
113local function GetRarityColor(rarity)
114 return RARITY_COLORS[rarity] or RARITY_COLORS.Common
115end
116
117-- ============================================
118-- UI CONSTRUCTION
119-- ============================================
120local UI = {}
121
122function UI.Build()
123 -- ScreenGui
124 local screenGui = Create("ScreenGui", {
125 Name = "RPGInventoryGui",
126 Parent = playerGui,
127 ResetOnSpawn = false,
128 ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
129 Enabled = false,
130 })
131 UI.ScreenGui = screenGui
132
133 -- Main Frame
134 local mainFrame = Create("Frame", {
135 Name = "MainFrame",
136 Parent = screenGui,
137 AnchorPoint = Vector2.new(0.5, 0.5),
138 Position = UDim2.new(0.5, 0, 0.5, 0),
139 Size = UDim2.new(0, 700, 0, 500),
140 BackgroundColor3 = Color3.fromRGB(25, 25, 35),
141 BorderSizePixel = 0,
142 ClipsDescendants = true,
143 ZIndex = 10,
144 })
145 UI.MainFrame = mainFrame
146
147 -- Corner
148 Create("UICorner", {
149 CornerRadius = UDim.new(0, 12),
150 Parent = mainFrame,
151 })
152
153 -- Gradient Background
154 Create("UIGradient", {
155 Color = ColorSequence.new({
156 ColorSequenceKeypoint.new(0, Color3.fromRGB(30, 30, 45)),
157 ColorSequenceKeypoint.new(1, Color3.fromRGB(18, 18, 28)),
158 }),
159 Rotation = 135,
160 Parent = mainFrame,
161 })
162
163 -- Top Bar
164 local topBar = Create("Frame", {
165 Name = "TopBar",
166 Parent = mainFrame,
167 Size = UDim2.new(1, 0, 0, 50),
168 BackgroundColor3 = Color3.fromRGB(35, 35, 50),
169 BorderSizePixel = 0,
170 ZIndex = 11,
171 })
172
173 Create("UICorner", {
174 CornerRadius = UDim.new(0, 0),
175 Parent = topBar,
176 })
177
178 -- Title
179 Create("TextLabel", {
180 Name = "TitleLabel",
181 Parent = topBar,
182 Position = UDim2.new(0, 15, 0, 0),
183 Size = UDim2.new(0, 200, 1, 0),
184 BackgroundTransparency = 1,
185 Text = "INVENTORY",
186 TextColor3 = Color3.fromRGB(220, 220, 240),
187 TextSize = 22,
188 Font = Enum.Font.GothamBold,
189 TextXAlignment = Enum.TextXAlignment.Left,
190 ZIndex = 12,
191 })
192
193 -- Coin Balance
194 UI.CoinBalance = Create("TextLabel", {
195 Name = "CoinBalance",
196 Parent = topBar,
197 Position = UDim2.new(1, -180, 0, 10),
198 Size = UDim2.new(0, 130, 0, 30),
199 BackgroundColor3 = Color3.fromRGB(45, 35, 25),
200 Text = "Coins: 1,250",
201 TextColor3 = Color3.fromRGB(255, 200, 50),
202 TextSize = 16,
203 Font = Enum.Font.GothamSemibold,
204 ZIndex = 12,
205 })
206 Create("UICorner", {CornerRadius = UDim.new(0, 6), Parent = UI.CoinBalance})
207
208 -- Close Button
209 local closeButton = Create("TextButton", {
210 Name = "CloseButton",
211 Parent = topBar,
212 Position = UDim2.new(1, -45, 0, 8),
213 Size = UDim2.new(0, 34, 0, 34),
214 BackgroundColor3 = Color3.fromRGB(180, 50, 50),
215 Text = "X",
216 TextColor3 = Color3.fromRGB(255, 255, 255),
217 TextSize = 18,
218 Font = Enum.Font.GothamBold,
219 ZIndex = 12,
220 })
221 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = closeButton})
222
223 -- Equipment Panel (Left Side)
224 local equipPanel = Create("Frame", {
225 Name = "EquipmentPanel",
226 Parent = mainFrame,
227 Position = UDim2.new(0, 0, 0, 50),
228 Size = UDim2.new(0, 210, 1, -100),
229 BackgroundColor3 = Color3.fromRGB(30, 30, 42),
230 BorderSizePixel = 0,
231 ZIndex = 11,
232 })
233
234 Create("TextLabel", {
235 Name = "EquipmentTitle",
236 Parent = equipPanel,
237 Position = UDim2.new(0, 0, 0, 5),
238 Size = UDim2.new(1, 0, 0, 30),
239 BackgroundTransparency = 1,
240 Text = "EQUIPPED",
241 TextColor3 = Color3.fromRGB(180, 180, 200),
242 TextSize = 16,
243 Font = Enum.Font.GothamBold,
244 ZIndex = 12,
245 })
246
247 -- Equipment Slots
248 UI.EquipSlots = {}
249 for slotType, slotConfig in pairs(EQUIPMENT_SLOTS) do
250 local slotFrame = Create("Frame", {
251 Name = slotType .. "Slot",
252 Parent = equipPanel,
253 Position = slotConfig.Position,
254 Size = UDim2.new(0, 64, 0, 64),
255 BackgroundColor3 = Color3.fromRGB(40, 40, 55),
256 BorderSizePixel = 0,
257 ZIndex = 12,
258 })
259 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = slotFrame})
260 local stroke = Create("UIStroke", {
261 Color = Color3.fromRGB(80, 80, 100),
262 Thickness = 2,
263 Parent = slotFrame,
264 })
265 Create("ImageLabel", {
266 Name = "ItemIcon",
267 Parent = slotFrame,
268 Size = UDim2.new(1, -8, 1, -8),
269 Position = UDim2.new(0, 4, 0, 4),
270 BackgroundTransparency = 1,
271 Image = "",
272 ZIndex = 13,
273 })
274 Create("TextLabel", {
275 Name = "SlotLabel",
276 Parent = slotFrame,
277 Size = UDim2.new(1, 0, 0, 20),
278 Position = UDim2.new(0, 0, 1, 2),
279 BackgroundTransparency = 1,
280 Text = slotConfig.Label,
281 TextColor3 = Color3.fromRGB(120, 120, 140),
282 TextSize = 12,
283 Font = Enum.Font.Gotham,
284 ZIndex = 13,
285 })
286 UI.EquipSlots[slotType] = {Frame = slotFrame, Stroke = stroke, Icon = slotFrame.ItemIcon}
287 end
288
289 -- Inventory Grid (Right Side)
290 local inventoryPanel = Create("Frame", {
291 Name = "InventoryPanel",
292 Parent = mainFrame,
293 Position = UDim2.new(0, 215, 0, 55),
294 Size = UDim2.new(1, -225, 1, -110),
295 BackgroundColor3 = Color3.fromRGB(28, 28, 40),
296 BorderSizePixel = 0,
297 ZIndex = 11,
298 })
299 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = inventoryPanel})
300
301 local scrollFrame = Create("ScrollingFrame", {
302 Name = "InventoryGrid",
303 Parent = inventoryPanel,
304 Size = UDim2.new(1, -10, 1, -10),
305 Position = UDim2.new(0, 5, 0, 5),
306 BackgroundTransparency = 1,
307 ScrollBarThickness = 6,
308 ScrollBarImageColor3 = Color3.fromRGB(80, 80, 100),
309 CanvasSize = UDim2.new(0, 0, 0, 0),
310 ZIndex = 12,
311 })
312
313 Create("UIGridLayout", {
314 CellSize = UDim2.new(0, CONFIG.SlotSize, 0, CONFIG.SlotSize),
315 CellPadding = UDim2.new(0, CONFIG.SlotPadding, 0, CONFIG.SlotPadding),
316 SortOrder = Enum.SortOrder.Name,
317 Parent = scrollFrame,
318 })
319
320 UI.InventorySlots = {}
321 local totalSlots = CONFIG.InventoryRows * CONFIG.InventoryCols
322 for i = 1, totalSlots do
323 local slotFrame = Create("Frame", {
324 Name = "Slot_" .. string.format("%02d", i),
325 Parent = scrollFrame,
326 Size = UDim2.new(0, CONFIG.SlotSize, 0, CONFIG.SlotSize),
327 BackgroundColor3 = Color3.fromRGB(38, 38, 52),
328 BorderSizePixel = 0,
329 ZIndex = 13,
330 })
331 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = slotFrame})
332 local stroke = Create("UIStroke", {
333 Color = Color3.fromRGB(70, 70, 90),
334 Thickness = 1,
335 Parent = slotFrame,
336 })
337 local icon = Create("ImageLabel", {
338 Name = "ItemIcon",
339 Parent = slotFrame,
340 Size = UDim2.new(1, -8, 1, -8),
341 Position = UDim2.new(0, 4, 0, 4),
342 BackgroundTransparency = 1,
343 Image = "",
344 ZIndex = 14,
345 })
346 local qty = Create("TextLabel", {
347 Name = "QuantityLabel",
348 Parent = slotFrame,
349 Size = UDim2.new(0, 24, 0, 18),
350 Position = UDim2.new(1, -26, 1, -20),
351 BackgroundColor3 = Color3.fromRGB(0, 0, 0),
352 BackgroundTransparency = 0.5,
353 Text = "",
354 TextColor3 = Color3.fromRGB(255, 255, 255),
355 TextSize = 12,
356 Font = Enum.Font.GothamBold,
357 ZIndex = 15,
358 })
359 Create("UICorner", {CornerRadius = UDim.new(0, 4), Parent = qty})
360
361 UI.InventorySlots[i] = {
362 Frame = slotFrame,
363 Stroke = stroke,
364 Icon = icon,
365 Quantity = qty,
366 }
367 end
368
369 -- Bottom Bar with Play, Settings, Store buttons
370 local bottomBar = Create("Frame", {
371 Name = "BottomBar",
372 Parent = mainFrame,
373 Position = UDim2.new(0, 0, 1, -50),
374 Size = UDim2.new(1, 0, 0, 50),
375 BackgroundColor3 = Color3.fromRGB(35, 35, 50),
376 BorderSizePixel = 0,
377 ZIndex = 11,
378 })
379
380 local bottomLayout = Create("UIListLayout", {
381 FillDirection = Enum.FillDirection.Horizontal,
382 HorizontalAlignment = Enum.HorizontalAlignment.Center,
383 VerticalAlignment = Enum.VerticalAlignment.Center,
384 Padding = UDim.new(0, 12),
385 Parent = bottomBar,
386 })
387
388 -- Play Button
389 UI.PlayButton = Create("TextButton", {
390 Name = "PlayButton",
391 Parent = bottomBar,
392 Size = UDim2.new(0, 100, 0, 36),
393 BackgroundColor3 = Color3.fromRGB(40, 160, 60),
394 Text = "Play",
395 TextColor3 = Color3.fromRGB(255, 255, 255),
396 TextSize = 16,
397 Font = Enum.Font.GothamBold,
398 ZIndex = 12,
399 })
400 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = UI.PlayButton})
401
402 -- Settings Button
403 UI.SettingsButton = Create("TextButton", {
404 Name = "SettingsButton",
405 Parent = bottomBar,
406 Size = UDim2.new(0, 100, 0, 36),
407 BackgroundColor3 = Color3.fromRGB(80, 80, 120),
408 Text = "Settings",
409 TextColor3 = Color3.fromRGB(255, 255, 255),
410 TextSize = 16,
411 Font = Enum.Font.GothamBold,
412 ZIndex = 12,
413 })
414 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = UI.SettingsButton})
415
416 -- Store Button
417 UI.StoreButton = Create("TextButton", {
418 Name = "StoreButton",
419 Parent = bottomBar,
420 Size = UDim2.new(0, 100, 0, 36),
421 BackgroundColor3 = Color3.fromRGB(200, 140, 40),
422 Text = "Store",
423 TextColor3 = Color3.fromRGB(255, 255, 255),
424 TextSize = 16,
425 Font = Enum.Font.GothamBold,
426 ZIndex = 12,
427 })
428 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = UI.StoreButton})
429
430 -- Tooltip Frame
431 UI.TooltipFrame = Create("Frame", {
432 Name = "TooltipFrame",
433 Parent = screenGui,
434 Size = UDim2.new(0, 220, 0, 130),
435 BackgroundColor3 = Color3.fromRGB(35, 35, 50),
436 BorderSizePixel = 0,
437 Visible = false,
438 ZIndex = 100,
439 })
440 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = UI.TooltipFrame})
441 UI.TooltipStroke = Create("UIStroke", {
442 Color = Color3.fromRGB(100, 100, 120),
443 Thickness = 2,
444 Parent = UI.TooltipFrame,
445 })
446 UI.TooltipName = Create("TextLabel", {
447 Name = "ItemName",
448 Parent = UI.TooltipFrame,
449 Position = UDim2.new(0, 10, 0, 8),
450 Size = UDim2.new(1, -20, 0, 24),
451 BackgroundTransparency = 1,
452 Text = "Item Name",
453 TextColor3 = Color3.fromRGB(255, 255, 255),
454 TextSize = 16,
455 Font = Enum.Font.GothamBold,
456 TextXAlignment = Enum.TextXAlignment.Left,
457 ZIndex = 101,
458 })
459 UI.TooltipRarity = Create("TextLabel", {
460 Name = "ItemRarity",
461 Parent = UI.TooltipFrame,
462 Position = UDim2.new(0, 10, 0, 34),
463 Size = UDim2.new(1, -20, 0, 18),
464 BackgroundTransparency = 1,
465 Text = "Common",
466 TextColor3 = Color3.fromRGB(169, 169, 169),
467 TextSize = 13,
468 Font = Enum.Font.GothamSemibold,
469 TextXAlignment = Enum.TextXAlignment.Left,
470 ZIndex = 101,
471 })
472 UI.TooltipDesc = Create("TextLabel", {
473 Name = "ItemDescription",
474 Parent = UI.TooltipFrame,
475 Position = UDim2.new(0, 10, 0, 56),
476 Size = UDim2.new(1, -20, 0, 40),
477 BackgroundTransparency = 1,
478 Text = "Item description goes here.",
479 TextColor3 = Color3.fromRGB(180, 180, 200),
480 TextSize = 12,
481 Font = Enum.Font.Gotham,
482 TextXAlignment = Enum.TextXAlignment.Left,
483 TextWrapped = true,
484 ZIndex = 101,
485 })
486 UI.TooltipStats = Create("TextLabel", {
487 Name = "ItemStats",
488 Parent = UI.TooltipFrame,
489 Position = UDim2.new(0, 10, 0, 100),
490 Size = UDim2.new(1, -20, 0, 22),
491 BackgroundTransparency = 1,
492 Text = "ATK: +10 | DEF: +5",
493 TextColor3 = Color3.fromRGB(100, 220, 100),
494 TextSize = 12,
495 Font = Enum.Font.GothamSemibold,
496 TextXAlignment = Enum.TextXAlignment.Left,
497 ZIndex = 101,
498 })
499
500 -- Drag Ghost
501 UI.DragGhost = Create("Frame", {
502 Name = "DragGhost",
503 Parent = screenGui,
504 Size = UDim2.new(0, CONFIG.SlotSize, 0, CONFIG.SlotSize),
505 BackgroundColor3 = Color3.fromRGB(50, 50, 70),
506 BackgroundTransparency = 0.3,
507 BorderSizePixel = 0,
508 Visible = false,
509 ZIndex = 200,
510 })
511 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = UI.DragGhost})
512 UI.DragGhostIcon = Create("ImageLabel", {
513 Name = "ItemIcon",
514 Parent = UI.DragGhost,
515 Size = UDim2.new(1, -8, 1, -8),
516 Position = UDim2.new(0, 4, 0, 4),
517 BackgroundTransparency = 1,
518 Image = "",
519 ZIndex = 201,
520 })
521 UI.DragGhostQty = Create("TextLabel", {
522 Name = "QuantityLabel",
523 Parent = UI.DragGhost,
524 Size = UDim2.new(0, 24, 0, 18),
525 Position = UDim2.new(1, -26, 1, -20),
526 BackgroundColor3 = Color3.fromRGB(0, 0, 0),
527 BackgroundTransparency = 0.5,
528 Text = "",
529 TextColor3 = Color3.fromRGB(255, 255, 255),
530 TextSize = 12,
531 Font = Enum.Font.GothamBold,
532 ZIndex = 202,
533 })
534
535 -- Action Menu (Right-click context menu)
536 UI.ActionMenu = Create("Frame", {
537 Name = "ActionMenu",
538 Parent = screenGui,
539 Size = UDim2.new(0, 130, 0, 140),
540 BackgroundColor3 = Color3.fromRGB(40, 40, 55),
541 BorderSizePixel = 0,
542 Visible = false,
543 ZIndex = 300,
544 })
545 Create("UICorner", {CornerRadius = UDim.new(0, 8), Parent = UI.ActionMenu})
546 Create("UIListLayout", {
547 Padding = UDim.new(0, 2),
548 Parent = UI.ActionMenu,
549 })
550
551 local actions = {"Use", "Equip", "Drop", "Destroy"}
552 local actionColors = {
553 Use = Color3.fromRGB(50, 130, 60),
554 Equip = Color3.fromRGB(50, 90, 150),
555 Drop = Color3.fromRGB(140, 120, 40),
556 Destroy = Color3.fromRGB(160, 50, 50),
557 }
558 UI.ActionButtons = {}
559 for _, action in ipairs(actions) do
560 local btn = Create("TextButton", {
561 Name = action .. "Button",
562 Parent = UI.ActionMenu,
563 Size = UDim2.new(1, -8, 0, 30),
564 Position = UDim2.new(0, 4, 0, 0),
565 BackgroundColor3 = actionColors[action],
566 Text = action,
567 TextColor3 = Color3.fromRGB(255, 255, 255),
568 TextSize = 14,
569 Font = Enum.Font.GothamSemibold,
570 ZIndex = 301,
571 })
572 Create("UICorner", {CornerRadius = UDim.new(0, 6), Parent = btn})
573 UI.ActionButtons[action] = btn
574 end
575
576 return UI
577end
578
579-- ============================================
580-- DRAG AND DROP SYSTEM
581-- ============================================
582function UI.SetupDragAndDrop()
583 local dragStartPos = nil
584 local dragStartScreenPos = nil
585 local dragSlotIndex = nil
586
587 for i, slot in ipairs(UI.InventorySlots) do
588 slot.Frame.InputBegan:Connect(function(input)
589 if input.UserInputType ~= Enum.UserInputType.MouseButton1 and
590 input.UserInputType ~= Enum.UserInputType.Touch then
591 return
592 end
593
594 local item = State.Inventory[i]
595 if not item then return end
596
597 dragStartPos = input.Position
598 dragStartScreenPos = input.Position
599 dragSlotIndex = i
600
601 -- Check for double click
602 local now = tick()
603 if State.LastClickedSlot == i and
604 (now - State.LastClickTime) < CONFIG.DoubleClickThreshold then
605 -- Double click - use item
606 Logic.UseItem(i)
607 dragSlotIndex = nil
608 return
609 end
610 State.LastClickTime = now
611 State.LastClickedSlot = i
612 end)
613
614 slot.Frame.InputChanged:Connect(function(input)
615 if input.UserInputType ~= Enum.UserInputType.MouseMovement and
616 input.UserInputType ~= Enum.UserInputType.Touch then
617 return
618 end
619 if not dragStartPos or not dragSlotIndex then return end
620
621 local delta = (input.Position - dragStartPos).Magnitude
622 if delta > CONFIG.DragThreshold then
623 -- Start dragging
624 if not State.Dragging then
625 Logic.StartDrag(dragSlotIndex)
626 end
627 -- Update ghost position
628 UI.DragGhost.Position = UDim2.new(0, input.Position.X - CONFIG.SlotSize/2,
629 0, input.Position.Y - CONFIG.SlotSize/2)
630 end
631
632 -- Tooltip
633 Logic.ShowTooltip(i, input.Position)
634 end)
635
636 slot.Frame.InputEnded:Connect(function(input)
637 if input.UserInputType ~= Enum.UserInputType.MouseButton1 and
638 input.UserInputType ~= Enum.UserInputType.Touch then
639 return
640 end
641 if State.Dragging then
642 Logic.EndDrag()
643 end
644 dragStartPos = nil
645 dragSlotIndex = nil
646 end)
647 end
648
649 -- Global input ended for drag cleanup
650 UserInputService.InputEnded:Connect(function(input)
651 if input.UserInputType == Enum.UserInputType.MouseButton1 and State.Dragging then
652 Logic.EndDrag()
653 dragStartPos = nil
654 dragSlotIndex = nil
655 end
656 end)
657end
658
659-- ============================================
660-- LOGIC SYSTEM
661-- ============================================
662local Logic = {}
663
664function Logic.StartDrag(slotIndex)
665 local item = State.Inventory[slotIndex]
666 if not item then return end
667
668 State.Dragging = {
669 SlotIndex = slotIndex,
670 ItemData = item,
671 }
672
673 UI.DragGhostIcon.Image = item.Icon or ""
674 UI.DragGhostQty.Text = item.Quantity and item.Quantity > 1 and tostring(item.Quantity) or ""
675 UI.DragGhost.Visible = true
676
677 -- Hide original icon temporarily
678 local slot = UI.InventorySlots[slotIndex]
679 Tween(slot.Icon, {ImageTransparency = 0.5}, 0.15)
680 Tween(slot.Frame, {BackgroundTransparency = 0.5}, 0.15)
681end
682
683function Logic.EndDrag()
684 if not State.Dragging then return end
685
686 local dragSlot = State.Dragging.SlotIndex
687 local mousePos = UserInputService:GetMouseLocation()
688
689 -- Check if dropped on equipment slot
690 for slotType, equipUI in pairs(UI.EquipSlots) do
691 local absPos = equipUI.Frame.AbsolutePosition
692 local absSize = equipUI.Frame.AbsoluteSize
693 if mousePos.X >= absPos.X and mousePos.X <= absPos.X + absSize.X and
694 mousePos.Y >= absPos.Y and mousePos.Y <= absPos.Y + absSize.Y then
695 Logic.EquipItem(dragSlot, slotType)
696 break
697 end
698 end
699
700 -- Check if dropped on another inventory slot
701 for i, slot in ipairs(UI.InventorySlots) do
702 if i ~= dragSlot then
703 local absPos = slot.Frame.AbsolutePosition
704 local absSize = slot.Frame.AbsoluteSize
705 if mousePos.X >= absPos.X and mousePos.X <= absPos.X + absSize.X and
706 mousePos.Y >= absPos.Y and mousePos.Y <= absPos.Y + absSize.Y then
707 Logic.SwapSlots(dragSlot, i)
708 break
709 end
710 end
711 end
712
713 -- Cleanup drag
714 UI.DragGhost.Visible = false
715 local origSlot = UI.InventorySlots[dragSlot]
716 Tween(origSlot.Icon, {ImageTransparency = 0}, 0.15)
717 Tween(origSlot.Frame, {BackgroundTransparency = 0}, 0.15)
718
719 State.Dragging = nil
720end
721
722function Logic.SwapSlots(fromIndex, toIndex)
723 -- Swap local state
724 State.Inventory[fromIndex], State.Inventory[toIndex] =
725 State.Inventory[toIndex], State.Inventory[fromIndex]
726 Logic.RefreshSlots()
727end
728
729function Logic.EquipItem(slotIndex, slotType)
730 local item = State.Inventory[slotIndex]
731 if not item then return end
732 if item.SlotType and item.SlotType ~= slotType then
733 -- Wrong slot type
734 return
735 end
736
737 -- Unequip current if any
738 if State.Equipped[slotType] then
739 Logic.UnequipSlot(slotType)
740 end
741
742 -- Equip new item
743 State.Equipped[slotType] = item
744 EquipItem:FireServer(slotIndex, slotType)
745
746 Logic.RefreshEquipSlots()
747 Logic.RefreshSlots()
748end
749
750function Logic.UnequipSlot(slotType)
751 State.Equipped[slotType] = nil
752 UnequipItem:FireServer(slotType)
753 Logic.RefreshEquipSlots()
754end
755
756function Logic.UseItem(slotIndex)
757 local item = State.Inventory[slotIndex]
758 if not item then return end
759 if not item.Usable then return end
760
761 UseItem:FireServer(slotIndex)
762 -- Reduce quantity locally for immediate feedback
763 if item.Quantity and item.Quantity > 1 then
764 item.Quantity = item.Quantity - 1
765 else
766 State.Inventory[slotIndex] = nil
767 end
768 Logic.RefreshSlots()
769end
770
771function Logic.DropItem(slotIndex)
772 local item = State.Inventory[slotIndex]
773 if not item then return end
774
775 DropItem:FireServer(slotIndex)
776 State.Inventory[slotIndex] = nil
777 Logic.RefreshSlots()
778end
779
780function Logic.DestroyItem(slotIndex)
781 local item = State.Inventory[slotIndex]
782 if not item then return end
783
784 DestroyItem:FireServer(slotIndex)
785 State.Inventory[slotIndex] = nil
786 Logic.RefreshSlots()
787end
788
789function Logic.ShowTooltip(slotIndex, screenPos)
790 local item = State.Inventory[slotIndex]
791 if not item then
792 UI.TooltipFrame.Visible = false
793 State.TooltipVisible = false
794 return
795 end
796
797 UI.TooltipName.Text = item.Name or "Unknown Item"
798 UI.TooltipName.TextColor3 = GetRarityColor(item.Rarity or "Common")
799 UI.TooltipRarity.Text = item.Rarity or "Common"
800 UI.TooltipRarity.TextColor3 = GetRarityColor(item.Rarity or "Common")
801 UI.TooltipDesc.Text = item.Description or "No description available."
802 UI.TooltipStats.Text = Logic.FormatStats(item.Stats)
803 UI.TooltipStroke.Color = GetRarityColor(item.Rarity or "Common")
804
805 -- Position tooltip near mouse but keep on screen
806 local x = screenPos.X + 20
807 local y = screenPos.Y + 20
808 local screenSize = workspace.CurrentCamera.ViewportSize
809 if x + 220 > screenSize.X then x = screenPos.X - 240 end
810 if y + 130 > screenSize.Y then y = screenPos.Y - 150 end
811
812 UI.TooltipFrame.Position = UDim2.new(0, x, 0, y)
813 UI.TooltipFrame.Visible = true
814 State.TooltipVisible = true
815end
816
817function Logic.HideTooltip()
818 UI.TooltipFrame.Visible = false
819 State.TooltipVisible = false
820end
821
822function Logic.FormatStats(stats)
823 if not stats then return "" end
824 local parts = {}
825 for stat, value in pairs(stats) do
826 local sign = value >= 0 and "+" or ""
827 table.insert(parts, stat .. ": " .. sign .. tostring(value))
828 end
829 return table.concat(parts, " | ")
830end
831
832function Logic.RefreshSlots()
833 for i, slot in ipairs(UI.InventorySlots) do
834 local item = State.Inventory[i]
835 if item then
836 slot.Icon.Image = item.Icon or ""
837 slot.Quantity.Text = item.Quantity and item.Quantity > 1 and tostring(item.Quantity) or ""
838 slot.Stroke.Color = GetRarityColor(item.Rarity or "Common")
839 slot.Stroke.Thickness = 1 + (RARITY_GLOWS[item.Rarity] or 0) * 0.5
840 else
841 slot.Icon.Image = ""
842 slot.Quantity.Text = ""
843 slot.Stroke.Color = Color3.fromRGB(70, 70, 90)
844 slot.Stroke.Thickness = 1
845 end
846 end
847end
848
849function Logic.RefreshEquipSlots()
850 for slotType, equipUI in pairs(UI.EquipSlots) do
851 local item = State.Equipped[slotType]
852 if item then
853 equipUI.Icon.Image = item.Icon or ""
854 equipUI.Stroke.Color = GetRarityColor(item.Rarity or "Common")
855 equipUI.Stroke.Thickness = 2 + (RARITY_GLOWS[item.Rarity] or 0)
856 else
857 equipUI.Icon.Image = ""
858 equipUI.Stroke.Color = Color3.fromRGB(80, 80, 100)
859 equipUI.Stroke.Thickness = 2
860 end
861 end
862end
863
864-- ============================================
865-- INPUT HANDLING
866-- ============================================
867function UI.SetupInput()
868 -- Toggle inventory with "I" key
869 UserInputService.InputBegan:Connect(function(input, gameProcessed)
870 if gameProcessed then return end
871 if input.KeyCode == Enum.KeyCode.I then
872 Logic.ToggleInventory()
873 end
874 end)
875
876 -- Close button
877 UI.MainFrame.TopBar.CloseButton.MouseButton1Click:Connect(function()
878 Logic.HideInventory()
879 end)
880
881 -- Play button
882 UI.PlayButton.MouseButton1Click:Connect(function()
883 Logic.HideInventory()
884 -- Resume game / close menus
885 end)
886
887 -- Settings button
888 UI.SettingsButton.MouseButton1Click:Connect(function()
889 -- Open settings (trigger other GUI)
890 print("Settings clicked")
891 end)
892
893 -- Store button
894 UI.StoreButton.MouseButton1Click:Connect(function()
895 -- Open store (trigger other GUI)
896 print("Store clicked")
897 end)
898
899 -- Action menu buttons
900 UI.ActionButtons.Use.MouseButton1Click:Connect(function()
901 if State.ActionSlot then Logic.UseItem(State.ActionSlot) end
902 Logic.HideActionMenu()
903 end)
904 UI.ActionButtons.Equip.MouseButton1Click:Connect(function()
905 if State.ActionSlot then
906 local item = State.Inventory[State.ActionSlot]
907 if item and item.SlotType then
908 Logic.EquipItem(State.ActionSlot, item.SlotType)
909 end
910 end
911 Logic.HideActionMenu()
912 end)
913 UI.ActionButtons.Drop.MouseButton1Click:Connect(function()
914 if State.ActionSlot then Logic.DropItem(State.ActionSlot) end
915 Logic.HideActionMenu()
916 end)
917 UI.ActionButtons.Destroy.MouseButton1Click:Connect(function()
918 if State.ActionSlot then Logic.DestroyItem(State.ActionSlot) end
919 Logic.HideActionMenu()
920 end)
921
922 -- Right-click for context menu
923 UserInputService.InputBegan:Connect(function(input, gameProcessed)
924 if gameProcessed then return end
925 if input.UserInputType == Enum.UserInputType.MouseButton2 then
926 -- Find which slot was right-clicked
927 local mousePos = UserInputService:GetMouseLocation()
928 for i, slot in ipairs(UI.InventorySlots) do
929 local absPos = slot.Frame.AbsolutePosition
930 local absSize = slot.Frame.AbsoluteSize
931 if mousePos.X >= absPos.X and mousePos.X <= absPos.X + absSize.X and
932 mousePos.Y >= absPos.Y and mousePos.Y <= absPos.Y + absSize.Y then
933 Logic.ShowActionMenu(i, mousePos)
934 break
935 end
936 end
937 end
938 end)
939
940 -- Close action menu on click elsewhere
941 UserInputService.InputBegan:Connect(function(input)
942 if input.UserInputType == Enum.UserInputType.MouseButton1 then
943 Logic.HideActionMenu()
944 end
945 end)
946
947 -- Hide tooltip when mouse leaves inventory area
948 UI.MainFrame.MouseLeave:Connect(function()
949 Logic.HideTooltip()
950 end)
951end
952
953function Logic.ShowActionMenu(slotIndex, position)
954 State.ActionSlot = slotIndex
955 State.ActionMenuVisible = true
956 UI.ActionMenu.Position = UDim2.new(0, position.X, 0, position.Y)
957 UI.ActionMenu.Visible = true
958end
959
960function Logic.HideActionMenu()
961 State.ActionMenuVisible = false
962 State.ActionSlot = nil
963 UI.ActionMenu.Visible = false
964end
965
966function Logic.ToggleInventory()
967 if State.IsVisible then
968 Logic.HideInventory()
969 else
970 Logic.ShowInventory()
971 end
972end
973
974function Logic.ShowInventory()
975 State.IsVisible = true
976 UI.ScreenGui.Enabled = true
977 UI.MainFrame.Size = UDim2.new(0, 600, 0, 400)
978 Tween(UI.MainFrame, {Size = UDim2.new(0, 700, 0, 500)}, 0.3, Enum.EasingStyle.Back, Enum.EasingDirection.Out)
979 Logic.RefreshSlots()
980 Logic.RefreshEquipSlots()
981end
982
983function Logic.HideInventory()
984 State.IsVisible = false
985 Tween(UI.MainFrame, {Size = UDim2.new(0, 600, 0, 400)}, 0.2)
986 task.delay(0.2, function()
987 if not State.IsVisible then
988 UI.ScreenGui.Enabled = false
989 end
990 end)
991end
992
993-- ============================================
994-- DATA SYNC
995-- ============================================
996function Logic.LoadInventory()
997 local data = RequestInventory:InvokeServer()
998 if data then
999 State.Inventory = data.Inventory or {}
1000 State.Equipped = data.Equipped or {}
1001 Logic.RefreshSlots()
1002 Logic.RefreshEquipSlots()
1003 end
1004end
1005
1006-- ============================================
1007-- DEMO DATA
1008-- ============================================
1009function Logic.LoadDemoData()
1010 State.Inventory = {
1011 [1] = {Name = "Iron Sword", Rarity = "Common", Icon = "rbxassetid://12345",
1012 Description = "A basic iron sword.", SlotType = "Weapon",
1013 Usable = false, Stats = {ATK = 15, SPD = 2}},
1014 [2] = {Name = "Healing Potion", Rarity = "Common", Icon = "rbxassetid://12346",
1015 Description = "Restores 50 HP.", Usable = true, Quantity = 5,
1016 Stats = {HP = 50}},
1017 [3] = {Name = "Dragon Armor", Rarity = "Legendary", Icon = "rbxassetid://12347",
1018 Description = "Forged from dragon scales.", SlotType = "Armor",
1019 Usable = false, Stats = {DEF = 45, HP = 100}},
1020 [5] = {Name = "Mystic Boots", Rarity = "Rare", Icon = "rbxassetid://12348",
1021 Description = "Boots infused with wind magic.", SlotType = "Boots",
1022 Usable = false, Stats = {SPD = 15, DEF = 8}},
1023 [8] = {Name = "Phoenix Feather", Rarity = "Epic", Icon = "rbxassetid://12349",
1024 Description = "A rare feather from a phoenix.", Usable = true, Quantity = 2,
1025 Stats = {HP = 200}},
1026 [12] = {Name = "Steel Helmet", Rarity = "Uncommon", Icon = "rbxassetid://12350",
1027 Description = "Reinforced steel helmet.", SlotType = "Helmet",
1028 Usable = false, Stats = {DEF = 12}},
1029 }
1030
1031 State.Equipped = {
1032 Helmet = {Name = "Steel Helmet", Rarity = "Uncommon", Icon = "rbxassetid://12350",
1033 Description = "Reinforced steel helmet.", SlotType = "Helmet",
1034 Stats = {DEF = 12}},
1035 }
1036
1037 Logic.RefreshSlots()
1038 Logic.RefreshEquipSlots()
1039end
1040
1041-- ============================================
1042-- INITIALIZATION
1043-- ============================================
1044UI.Build()
1045UI.SetupDragAndDrop()
1046UI.SetupInput()
1047
1048-- Load inventory data from server
1049-- Logic.LoadInventory()
1050
1051-- Or load demo data for preview
1052Logic.LoadDemoData()
1053
1054print("RPG Inventory System initialized. Press 'I' to toggle.")

Code preview

RPG Inventory

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