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

FPS HUD Roblox GUI Template with Ammo / Health / Crosshair

A tactical FPS HUD with ammo counter, health bar, crosshair, and kill feed placeholder. Designed for performance-focused first-person shooter experiences on Roblox. Features a dark tactical aesthetic inspired by modern military shooters, with high-contrast UI elements that remain readable during intense gameplay.

HUDMarketplace· Open in editor for free during beta
FPS HUD Roblox GUI template — Ammo / Health / Crosshair, dark hud layout, screenshot 1
FPS HUD Roblox GUI template — screenshot 1 of 1, showing ammo / health / crosshair on a dark hud layout for desktop.
Open in Web EditorChecking access…

Live preview

FPS HUD

1920×1080
Zoom100%
Desktop (FHD)
ScreenGui
Frame
Frame
30 / 90
Frame
Frame
Frame
A tactical FPS HUD with ammo counter, health bar, crosshair, and kill feed placeholder. Designed for performance-focused first-person shooter experiences on Roblox. Features a dark tactical aesthetic inspired by modern military shooters, with high-contrast UI elements that remain readable during intense gameplay.

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

What's inside

How to use this template

The FPS HUD template shows ammo, health, crosshair, and a kill feed for first-person shooters. Paste the client Luau into StarterGui and the HUD appears, with health bottom-left, ammo bottom-right, and the crosshair centered. The ammo counter updates when the player fires or reloads, and turns red below 25% magazine. The health bar tweens to the new ratio on damage. The crosshair is a small Frame anchored to the screen center. The kill feed is a UIListLayout that fades entries out after 4 seconds. The layout uses Scale-based sizing, so it works on 16:9 and ultrawide. To customize, change the crosshair color and size in the properties panel. Wire the ammo and health updates to your weapon and damage systems. Test in Studio by firing the update events manually and confirming the HUD responds.

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.

fps-hud.lua
lua
1--[[
2 FPS HUD - Client LocalScript
3 A tactical FPS HUD with ammo counter, health bar, crosshair, and kill feed.
4 Place in: StarterPlayer > StarterPlayerScripts
5--]]
6
7local Players = game:GetService("Players")
8local TweenService = game:GetService("TweenService")
9local UserInputService = game:GetService("UserInputService")
10local RunService = game:GetService("RunService")
11local ReplicatedStorage = game:GetService("ReplicatedStorage")
12
13local player = Players.LocalPlayer
14local playerGui = player:WaitForChild("PlayerGui")
15
16-- ============================================================
17-- REMOTE EVENTS (Created by Server Script)
18-- ============================================================
19local remotes = ReplicatedStorage:WaitForChild("FPS_HUD_Remotes")
20local updateHealthEvent = remotes:WaitForChild("UpdateHealth")
21local updateAmmoEvent = remotes:WaitForChild("UpdateAmmo")
22local updateScoreEvent = remotes:WaitForChild("UpdateScore")
23local killFeedEvent = remotes:WaitForChild("KillFeed")
24local hitMarkerEvent = remotes:WaitForChild("HitMarker")
25local damageIndicatorEvent = remotes:WaitForChild("DamageIndicator")
26local reloadEvent = remotes:WaitForChild("Reload")
27local weaponSwitchEvent = remotes:WaitForChild("WeaponSwitch")
28
29-- ============================================================
30-- CONFIGURATION
31-- ============================================================
32local CONFIG = {
33 -- Colors
34 CROSSHAIR_COLOR = Color3.fromRGB(0, 255, 100),
35 CROSSHAIR_HIT_COLOR = Color3.fromRGB(255, 50, 50),
36 HEALTH_HIGH = Color3.fromRGB(0, 255, 100),
37 HEALTH_MID = Color3.fromRGB(255, 200, 50),
38 HEALTH_LOW = Color3.fromRGB(255, 50, 50),
39 AMMO_COLOR = Color3.fromRGB(255, 255, 255),
40 AMMO_LOW_COLOR = Color3.fromRGB(255, 100, 100),
41 BG_DARK = Color3.fromRGB(20, 20, 20),
42 BG_TRANSPARENT = Color3.fromRGB(0, 0, 0),
43 TEXT_WHITE = Color3.fromRGB(240, 240, 240),
44 TEXT_GRAY = Color3.fromRGB(150, 150, 150),
45 HITMARKER_COLOR = Color3.fromRGB(255, 255, 255),
46 DAMAGE_COLOR = Color3.fromRGB(255, 0, 0),
47
48 -- Sizes
49 CROSSHAIR_SIZE = 12,
50 CROSSHAIR_THICKNESS = 2,
51 CROSSHAIR_GAP = 6,
52 CROSSHAIR_DOT_SIZE = 2,
53
54 -- Animation
55 TWEEN_INFO_FAST = TweenInfo.new(0.15, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
56 TWEEN_INFO_NORMAL = TweenInfo.new(0.3, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
57 TWEEN_INFO_SLOW = TweenInfo.new(0.5, Enum.EasingStyle.Quad, Enum.EasingDirection.Out),
58 HITMARKER_DURATION = 0.2,
59 DAMAGE_INDICATOR_DURATION = 0.6,
60 KILL_FEED_DURATION = 6,
61
62 -- Health thresholds
63 HEALTH_MID_THRESHOLD = 0.6,
64 HEALTH_LOW_THRESHOLD = 0.25,
65 AMMO_LOW_THRESHOLD = 0.25,
66}
67
68-- ============================================================
69-- STATE
70-- ============================================================
71local state = {
72 health = 100,
73 maxHealth = 100,
74 ammoCurrent = 30,
75 ammoReserve = 120,
76 ammoMax = 30,
77 score = 0,
78 kills = 0,
79 deaths = 0,
80 isReloading = false,
81 currentWeapon = "Assault Rifle",
82 crosshairVisible = true,
83 hitMarkerTimer = nil,
84 damageIndicators = {},
85 killFeedItems = {},
86}
87
88-- ============================================================
89-- HELPER FUNCTIONS
90-- ============================================================
91
92local function createInstance(className, props)
93 local instance = Instance.new(className)
94 for key, value in pairs(props) do
95n instance[key] = value
96 end
97 return instance
98end
99
100local function createCorner(parent, radius)
101 local corner = Instance.new("UICorner")
102 corner.CornerRadius = UDim.new(0, radius or 4)
103 corner.Parent = parent
104 return corner
105end
106
107local function createGradient(parent, color1, color2, rotation)
108 local gradient = Instance.new("UIGradient")
109 gradient.Color = ColorSequence.new({
110 ColorSequenceKeypoint.new(0, color1 or Color3.new(1, 1, 1)),
111 ColorSequenceKeypoint.new(1, color2 or Color3.new(0.5, 0.5, 0.5)),
112 })
113 gradient.Rotation = rotation or 0
114 gradient.Parent = parent
115 return gradient
116end
117
118local function lerpColor(a, b, t)
119 return Color3.new(
120 a.R + (b.R - a.R) * t,
121 a.G + (b.G - a.G) * t,
122 a.B + (b.B - a.B) * t
123 )
124end
125
126local function getHealthColor(ratio)
127 if ratio > CONFIG.HEALTH_MID_THRESHOLD then
128 local t = (ratio - CONFIG.HEALTH_MID_THRESHOLD) / (1 - CONFIG.HEALTH_MID_THRESHOLD)
129 return lerpColor(CONFIG.HEALTH_MID, CONFIG.HEALTH_HIGH, t)
130 elseif ratio > CONFIG.HEALTH_LOW_THRESHOLD then
131 local t = (ratio - CONFIG.HEALTH_LOW_THRESHOLD) / (CONFIG.HEALTH_MID_THRESHOLD - CONFIG.HEALTH_LOW_THRESHOLD)
132 return lerpColor(CONFIG.HEALTH_LOW, CONFIG.HEALTH_MID, t)
133 else
134 return CONFIG.HEALTH_LOW
135 end
136end
137
138-- ============================================================
139-- UI CONSTRUCTION
140-- ============================================================
141
142-- Main ScreenGui
143local screenGui = createInstance("ScreenGui", {
144 Name = "FPS_HUD",
145 ResetOnSpawn = false,
146 ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
147 Parent = playerGui,
148})
149
150-- --------------------------------------------------------
151-- CROSSHAIR
152-- --------------------------------------------------------
153local crosshairContainer = createInstance("Frame", {
154 Name = "CrosshairContainer",
155 Size = UDim2.fromOffset(40, 40),
156 Position = UDim2.fromScale(0.5, 0.5),
157 AnchorPoint = Vector2.new(0.5, 0.5),
158 BackgroundTransparency = 1,
159 ZIndex = 10,
160 Parent = screenGui,
161})
162
163local crosshairParts = {}
164
165-- Top line
166local chTop = createInstance("Frame", {
167 Name = "Crosshair_Top",
168 Size = UDim2.fromOffset(CONFIG.CROSSHAIR_THICKNESS, CONFIG.CROSSHAIR_SIZE),
169 Position = UDim2.fromScale(0.5, 0),
170 AnchorPoint = Vector2.new(0.5, 1),
171 BackgroundColor3 = CONFIG.CROSSHAIR_COLOR,
172 BorderSizePixel = 0,
173 ZIndex = 10,
174 Parent = crosshairContainer,
175})
176crosshairParts.Top = chTop
177
178-- Bottom line
179local chBottom = createInstance("Frame", {
180 Name = "Crosshair_Bottom",
181 Size = UDim2.fromOffset(CONFIG.CROSSHAIR_THICKNESS, CONFIG.CROSSHAIR_SIZE),
182 Position = UDim2.fromScale(0.5, 1),
183 AnchorPoint = Vector2.new(0.5, 0),
184 BackgroundColor3 = CONFIG.CROSSHAIR_COLOR,
185 BorderSizePixel = 0,
186 ZIndex = 10,
187 Parent = crosshairContainer,
188})
189crosshairParts.Bottom = chBottom
190
191-- Left line
192local chLeft = createInstance("Frame", {
193 Name = "Crosshair_Left",
194 Size = UDim2.fromOffset(CONFIG.CROSSHAIR_SIZE, CONFIG.CROSSHAIR_THICKNESS),
195 Position = UDim2.fromScale(0, 0.5),
196 AnchorPoint = Vector2.new(1, 0.5),
197 BackgroundColor3 = CONFIG.CROSSHAIR_COLOR,
198 BorderSizePixel = 0,
199 ZIndex = 10,
200 Parent = crosshairContainer,
201})
202crosshairParts.Left = chLeft
203
204-- Right line
205local chRight = createInstance("Frame", {
206 Name = "Crosshair_Right",
207 Size = UDim2.fromOffset(CONFIG.CROSSHAIR_SIZE, CONFIG.CROSSHAIR_THICKNESS),
208 Position = UDim2.fromScale(1, 0.5),
209 AnchorPoint = Vector2.new(0, 0.5),
210 BackgroundColor3 = CONFIG.CROSSHAIR_COLOR,
211 BorderSizePixel = 0,
212 ZIndex = 10,
213 Parent = crosshairContainer,
214})
215crosshairParts.Right = chRight
216
217-- Center dot
218local chDot = createInstance("Frame", {
219 Name = "Crosshair_Dot",
220 Size = UDim2.fromOffset(CONFIG.CROSSHAIR_DOT_SIZE, CONFIG.CROSSHAIR_DOT_SIZE),
221 Position = UDim2.fromScale(0.5, 0.5),
222 AnchorPoint = Vector2.new(0.5, 0.5),
223 BackgroundColor3 = CONFIG.CROSSHAIR_COLOR,
224 BorderSizePixel = 0,
225 ZIndex = 10,
226 Parent = crosshairContainer,
227})
228crosshairParts.Dot = chDot
229
230-- --------------------------------------------------------
231-- HEALTH BAR
232-- --------------------------------------------------------
233local healthContainer = createInstance("Frame", {
234 Name = "HealthBarContainer",
235 Size = UDim2.fromOffset(220, 60),
236 Position = UDim2.new(0, 20, 1, -80),
237 AnchorPoint = Vector2.new(0, 1),
238 BackgroundTransparency = 1,
239 ZIndex = 5,
240 Parent = screenGui,
241})
242
243local healthLabel = createInstance("TextLabel", {
244 Name = "HealthLabel",
245 Size = UDim2.fromOffset(40, 20),
246 Position = UDim2.fromOffset(0, 0),
247 BackgroundTransparency = 1,
248 Text = "HP",
249 TextColor3 = CONFIG.TEXT_GRAY,
250 TextSize = 14,
251 Font = Enum.Font.GothamBold,
252 TextXAlignment = Enum.TextXAlignment.Left,
253 ZIndex = 5,
254 Parent = healthContainer,
255})
256
257local healthBarBg = createInstance("Frame", {
258 Name = "HealthBarBg",
259 Size = UDim2.new(1, 0, 0, 24),
260 Position = UDim2.fromOffset(0, 22),
261 BackgroundColor3 = CONFIG.BG_DARK,
262 BackgroundTransparency = 0.3,
263 BorderSizePixel = 0,
264 ZIndex = 5,
265 Parent = healthContainer,
266})
267createCorner(healthBarBg, 6)
268
269local healthBarFill = createInstance("Frame", {
270 Name = "HealthBarFill",
271 Size = UDim2.fromScale(1, 1),
272 BackgroundColor3 = CONFIG.HEALTH_HIGH,
273 BorderSizePixel = 0,
274 ZIndex = 6,
275 Parent = healthBarBg,
276})
277createCorner(healthBarFill, 6)
278
279local healthValue = createInstance("TextLabel", {
280 Name = "HealthValue",
281 Size = UDim2.new(1, 0, 0, 24),
282 Position = UDim2.fromOffset(0, 22),
283 BackgroundTransparency = 1,
284 Text = "100 / 100",
285 TextColor3 = CONFIG.TEXT_WHITE,
286 TextSize = 14,
287 Font = Enum.Font.GothamBold,
288 ZIndex = 7,
289 Parent = healthContainer,
290})
291
292-- --------------------------------------------------------
293-- AMMO COUNTER
294-- --------------------------------------------------------
295local ammoContainer = createInstance("Frame", {
296 Name = "AmmoContainer",
297 Size = UDim2.fromOffset(180, 70),
298 Position = UDim2.new(1, -20, 1, -90),
299 AnchorPoint = Vector2.new(1, 1),
300 BackgroundTransparency = 1,
301 ZIndex = 5,
302 Parent = screenGui,
303})
304
305local ammoCurrent = createInstance("TextLabel", {
306 Name = "AmmoCurrent",
307 Size = UDim2.fromOffset(70, 50),
308 Position = UDim2.new(1, -160, 0, 0),
309 BackgroundTransparency = 1,
310 Text = tostring(state.ammoCurrent),
311 TextColor3 = CONFIG.AMMO_COLOR,
312 TextSize = 42,
313 Font = Enum.Font.GothamBlack,
314 TextXAlignment = Enum.TextXAlignment.Right,
315 ZIndex = 5,
316 Parent = ammoContainer,
317})
318
319local ammoDivider = createInstance("TextLabel", {
320 Name = "AmmoDivider",
321 Size = UDim2.fromOffset(20, 40),
322 Position = UDim2.new(1, -90, 0, 5),
323 BackgroundTransparency = 1,
324 Text = "/",
325 TextColor3 = CONFIG.TEXT_GRAY,
326 TextSize = 28,
327 Font = Enum.Font.GothamBold,
328 TextXAlignment = Enum.TextXAlignment.Center,
329 ZIndex = 5,
330 Parent = ammoContainer,
331})
332
333local ammoReserve = createInstance("TextLabel", {
334 Name = "AmmoReserve",
335 Size = UDim2.fromOffset(70, 40),
336 Position = UDim2.new(1, -20, 0, 10),
337 AnchorPoint = Vector2.new(1, 0),
338 BackgroundTransparency = 1,
339 Text = tostring(state.ammoReserve),
340 TextColor3 = CONFIG.TEXT_GRAY,
341 TextSize = 24,
342 Font = Enum.Font.GothamBold,
343 TextXAlignment = Enum.TextXAlignment.Left,
344 ZIndex = 5,
345 Parent = ammoContainer,
346})
347
348local weaponName = createInstance("TextLabel", {
349 Name = "WeaponName",
350 Size = UDim2.new(1, 0, 0, 18),
351 Position = UDim2.fromOffset(0, 52),
352 BackgroundTransparency = 1,
353 Text = string.upper(state.currentWeapon),
354 TextColor3 = CONFIG.TEXT_GRAY,
355 TextSize = 11,
356 Font = Enum.Font.GothamBold,
357 TextXAlignment = Enum.TextXAlignment.Right,
358 ZIndex = 5,
359 Parent = ammoContainer,
360})
361
362-- --------------------------------------------------------
363-- KILL FEED
364-- --------------------------------------------------------
365local killFeedContainer = createInstance("Frame", {
366 Name = "KillFeedContainer",
367 Size = UDim2.fromOffset(280, 200),
368 Position = UDim2.new(1, -20, 0, 20),
369 AnchorPoint = Vector2.new(1, 0),
370 BackgroundTransparency = 1,
371 ZIndex = 5,
372 Parent = screenGui,
373})
374
375local killFeedLayout = createInstance("UIListLayout", {
376 SortOrder = Enum.SortOrder.LayoutOrder,
377 VerticalAlignment = Enum.VerticalAlignment.Top,
378 HorizontalAlignment = Enum.HorizontalAlignment.Right,
379 Padding = UDim.new(0, 4),
380 Parent = killFeedContainer,
381})
382
383-- --------------------------------------------------------
384-- SCORE DISPLAY
385-- --------------------------------------------------------
386local scoreContainer = createInstance("Frame", {
387 Name = "ScoreContainer",
388 Size = UDim2.fromOffset(120, 80),
389 Position = UDim2.fromOffset(20, 20),
390 BackgroundTransparency = 1,
391 ZIndex = 5,
392 Parent = screenGui,
393})
394
395local scoreLabel = createInstance("TextLabel", {
396 Name = "ScoreLabel",
397 Size = UDim2.fromOffset(60, 16),
398 Position = UDim2.fromOffset(0, 0),
399 BackgroundTransparency = 1,
400 Text = "SCORE",
401 TextColor3 = CONFIG.TEXT_GRAY,
402 TextSize = 10,
403 Font = Enum.Font.GothamBold,
404 TextXAlignment = Enum.TextXAlignment.Left,
405 ZIndex = 5,
406 Parent = scoreContainer,
407})
408
409local scoreValue = createInstance("TextLabel", {
410 Name = "ScoreValue",
411 Size = UDim2.fromOffset(60, 26),
412 Position = UDim2.fromOffset(0, 16),
413 BackgroundTransparency = 1,
414 Text = "0",
415 TextColor3 = CONFIG.TEXT_WHITE,
416 TextSize = 22,
417 Font = Enum.Font.GothamBlack,
418 TextXAlignment = Enum.TextXAlignment.Left,
419 ZIndex = 5,
420 Parent = scoreContainer,
421})
422
423local killsLabel = createInstance("TextLabel", {
424 Name = "KillsLabel",
425 Size = UDim2.fromOffset(50, 16),
426 Position = UDim2.fromOffset(0, 44),
427 BackgroundTransparency = 1,
428 Text = "KILLS",
429 TextColor3 = CONFIG.TEXT_GRAY,
430 TextSize = 10,
431 Font = Enum.Font.GothamBold,
432 TextXAlignment = Enum.TextXAlignment.Left,
433 ZIndex = 5,
434 Parent = scoreContainer,
435})
436
437local killsValue = createInstance("TextLabel", {
438 Name = "KillsValue",
439 Size = UDim2.fromOffset(50, 20),
440 Position = UDim2.fromOffset(50, 44),
441 BackgroundTransparency = 1,
442 Text = "0",
443 TextColor3 = CONFIG.TEXT_WHITE,
444 TextSize = 14,
445 Font = Enum.Font.GothamBold,
446 TextXAlignment = Enum.TextXAlignment.Left,
447 ZIndex = 5,
448 Parent = scoreContainer,
449})
450
451local deathsLabel = createInstance("TextLabel", {
452 Name = "DeathsLabel",
453 Size = UDim2.fromOffset(50, 16),
454 Position = UDim2.fromOffset(0, 62),
455 BackgroundTransparency = 1,
456 Text = "DEATHS",
457 TextColor3 = CONFIG.TEXT_GRAY,
458 TextSize = 10,
459 Font = Enum.Font.GothamBold,
460 TextXAlignment = Enum.TextXAlignment.Left,
461 ZIndex = 5,
462 Parent = scoreContainer,
463})
464
465local deathsValue = createInstance("TextLabel", {
466 Name = "DeathsValue",
467 Size = UDim2.fromOffset(50, 20),
468 Position = UDim2.fromOffset(50, 62),
469 BackgroundTransparency = 1,
470 Text = "0",
471 TextColor3 = CONFIG.TEXT_WHITE,
472 TextSize = 14,
473 Font = Enum.Font.GothamBold,
474 TextXAlignment = Enum.TextXAlignment.Left,
475 ZIndex = 5,
476 Parent = scoreContainer,
477})
478
479-- --------------------------------------------------------
480-- HIT MARKER
481-- --------------------------------------------------------
482local hitMarker = createInstance("Frame", {
483 Name = "HitMarker",
484 Size = UDim2.fromOffset(24, 24),
485 Position = UDim2.fromScale(0.5, 0.5),
486 AnchorPoint = Vector2.new(0.5, 0.5),
487 BackgroundTransparency = 1,
488 ZIndex = 15,
489 Parent = screenGui,
490 Visible = false,
491})
492
493local hitParts = {}
494local hitConfigs = {
495 { name = "Hit_TL", pos = UDim2.fromScale(0, 0), anchor = Vector2.new(1, 1), size = UDim2.fromOffset(6, 2), rot = -45 },
496 { name = "Hit_TR", pos = UDim2.fromScale(1, 0), anchor = Vector2.new(0, 1), size = UDim2.fromOffset(6, 2), rot = 45 },
497 { name = "Hit_BL", pos = UDim2.fromScale(0, 1), anchor = Vector2.new(1, 0), size = UDim2.fromOffset(6, 2), rot = 45 },
498 { name = "Hit_BR", pos = UDim2.fromScale(1, 1), anchor = Vector2.new(0, 0), size = UDim2.fromOffset(6, 2), rot = -45 },
499}
500
501for _, cfg in ipairs(hitConfigs) do
502 local part = createInstance("Frame", {
503 Name = cfg.name,
504 Size = cfg.size,
505 Position = cfg.pos,
506 AnchorPoint = cfg.anchor,
507 BackgroundColor3 = CONFIG.HITMARKER_COLOR,
508 BorderSizePixel = 0,
509 Rotation = cfg.rot,
510 ZIndex = 15,
511 Parent = hitMarker,
512 })
513 table.insert(hitParts, part)
514end
515
516-- --------------------------------------------------------
517-- DAMAGE INDICATOR (Directional blood overlay)
518-- --------------------------------------------------------
519local damageIndicator = createInstance("Frame", {
520 Name = "DamageIndicator",
521 Size = UDim2.fromScale(1, 1),
522 Position = UDim2.fromScale(0.5, 0.5),
523 AnchorPoint = Vector2.new(0.5, 0.5),
524 BackgroundTransparency = 1,
525 ZIndex = 8,
526 Parent = screenGui,
527 Visible = false,
528})
529
530local damageParts = {}
531local damageConfigs = {
532 { name = "Damage_Top", pos = UDim2.new(0.35, 0, 0, 0), size = UDim2.new(0.3, 0, 0, 80), anchor = Vector2.new(0, 0) },
533 { name = "Damage_Bottom", pos = UDim2.new(0.35, 0, 1, 0), size = UDim2.new(0.3, 0, 0, 80), anchor = Vector2.new(0, 1) },
534 { name = "Damage_Left", pos = UDim2.new(0, 0, 0.35, 0), size = UDim2.new(0, 80, 0.3, 0), anchor = Vector2.new(0, 0) },
535 { name = "Damage_Right", pos = UDim2.new(1, 0, 0.35, 0), size = UDim2.new(0, 80, 0.3, 0), anchor = Vector2.new(1, 0) },
536}
537
538for _, cfg in ipairs(damageConfigs) do
539 local part = createInstance("Frame", {
540 Name = cfg.name,
541 Size = cfg.size,
542 Position = cfg.pos,
543 AnchorPoint = cfg.anchor,
544 BackgroundColor3 = CONFIG.DAMAGE_COLOR,
545 BackgroundTransparency = 1,
546 BorderSizePixel = 0,
547 ZIndex = 8,
548 Parent = damageIndicator,
549 })
550 local grad = createGradient(part, CONFIG.DAMAGE_COLOR, Color3.new(0, 0, 0), 90)
551 table.insert(damageParts, { frame = part, gradient = grad })
552end
553
554-- --------------------------------------------------------
555-- RELOAD BAR
556-- --------------------------------------------------------
557local reloadContainer = createInstance("Frame", {
558 Name = "ReloadBarContainer",
559 Size = UDim2.fromOffset(200, 30),
560 Position = UDim2.new(0.5, 0, 1, -130),
561 AnchorPoint = Vector2.new(0.5, 1),
562 BackgroundTransparency = 1,
563 ZIndex = 6,
564 Parent = screenGui,
565 Visible = false,
566})
567
568local reloadBarBg = createInstance("Frame", {
569 Name = "ReloadBarBg",
570 Size = UDim2.new(1, 0, 0, 8),
571 Position = UDim2.fromScale(0.5, 0.5),
572 AnchorPoint = Vector2.new(0.5, 0.5),
573 BackgroundColor3 = CONFIG.BG_DARK,
574 BackgroundTransparency = 0.5,
575 BorderSizePixel = 0,
576 ZIndex = 6,
577 Parent = reloadContainer,
578})
579createCorner(reloadBarBg, 4)
580
581local reloadBarFill = createInstance("Frame", {
582 Name = "ReloadBarFill",
583 Size = UDim2.fromScale(0, 1),
584 BackgroundColor3 = CONFIG.HEALTH_HIGH,
585 BorderSizePixel = 0,
586 ZIndex = 7,
587 Parent = reloadBarBg,
588})
589createCorner(reloadBarFill, 4)
590
591local reloadLabel = createInstance("TextLabel", {
592 Name = "ReloadLabel",
593 Size = UDim2.new(1, 0, 0, 20),
594 Position = UDim2.fromOffset(0, -12),
595 BackgroundTransparency = 1,
596 Text = "RELOADING...",
597 TextColor3 = CONFIG.TEXT_GRAY,
598 TextSize = 10,
599 Font = Enum.Font.GothamBold,
600 ZIndex = 7,
601 Parent = reloadContainer,
602})
603
604-- --------------------------------------------------------
605-- WEAPON SLOTS
606-- --------------------------------------------------------
607local weaponSlots = createInstance("Frame", {
608 Name = "WeaponSlots",
609 Size = UDim2.fromOffset(200, 30),
610 Position = UDim2.new(0.5, 0, 1, -40),
611 AnchorPoint = Vector2.new(0.5, 1),
612 BackgroundTransparency = 1,
613 ZIndex = 5,
614 Parent = screenGui,
615})
616
617local slotLayout = createInstance("UIListLayout", {
618 FillDirection = Enum.FillDirection.Horizontal,
619 HorizontalAlignment = Enum.HorizontalAlignment.Center,
620 VerticalAlignment = Enum.VerticalAlignment.Center,
621 Padding = UDim.new(0, 8),
622 Parent = weaponSlots,
623})
624
625local slot1 = createInstance("TextButton", {
626 Name = "Slot1",
627 Size = UDim2.fromOffset(90, 28),
628 BackgroundColor3 = CONFIG.BG_DARK,
629 BackgroundTransparency = 0.3,
630 Text = "1 RIFLE",
631 TextColor3 = CONFIG.TEXT_WHITE,
632 TextSize = 11,
633 Font = Enum.Font.GothamBold,
634 BorderSizePixel = 0,
635 ZIndex = 5,
636 Parent = weaponSlots,
637})
638createCorner(slot1, 4)
639
640local slot2 = createInstance("TextButton", {
641 Name = "Slot2",
642 Size = UDim2.fromOffset(90, 28),
643 BackgroundColor3 = CONFIG.BG_DARK,
644 BackgroundTransparency = 0.7,
645 Text = "2 PISTOL",
646 TextColor3 = CONFIG.TEXT_GRAY,
647 TextSize = 11,
648 Font = Enum.Font.GothamBold,
649 BorderSizePixel = 0,
650 ZIndex = 5,
651 Parent = weaponSlots,
652})
653createCorner(slot2, 4)
654
655-- ============================================================
656-- UPDATE FUNCTIONS
657-- ============================================================
658
659local function updateHealth(current, max)
660 state.health = current
661 state.maxHealth = max
662 local ratio = math.clamp(current / max, 0, 1)
663
664 -- Update fill width
665 local tween = TweenService:Create(healthBarFill, CONFIG.TWEEN_INFO_NORMAL, {
666 Size = UDim2.fromScale(ratio, 1),
667 })
668 tween:Play()
669
670 -- Update color based on health level
671 local targetColor = getHealthColor(ratio)
672 local colorTween = TweenService:Create(healthBarFill, CONFIG.TWEEN_INFO_NORMAL, {
673 BackgroundColor3 = targetColor,
674 })
675 colorTween:Play()
676
677 -- Update text
678 healthValue.Text = string.format("%d / %d", current, max)
679
680 -- Pulse animation on low health
681 if ratio <= CONFIG.HEALTH_LOW_THRESHOLD then
682 local pulseTween = TweenService:Create(healthBarFill, TweenInfo.new(0.5, Enum.EasingStyle.Sine, Enum.EasingDirection.InOut, -1, true), {
683 BackgroundColor3 = CONFIG.HEALTH_LOW,
684 })
685 pulseTween:Play()
686 end
687end
688
689local function updateAmmo(current, reserve)
690 state.ammoCurrent = current
691 state.ammoReserve = reserve
692
693 -- Animate current ammo change
694 local currentTween = TweenService:Create(ammoCurrent, CONFIG.TWEEN_INFO_FAST, {
695 TextTransparency = 0,
696 })
697 currentTween:Play()
698 ammoCurrent.Text = tostring(current)
699
700 -- Change color when low on ammo
701 local ammoRatio = current / state.ammoMax
702 if ammoRatio <= CONFIG.AMMO_LOW_THRESHOLD then
703 ammoCurrent.TextColor3 = CONFIG.AMMO_LOW_COLOR
704 else
705 ammoCurrent.TextColor3 = CONFIG.AMMO_COLOR
706 end
707
708 ammoReserve.Text = tostring(reserve)
709end
710
711local function updateScore(score, kills, deaths)
712 state.score = score
713 state.kills = kills
714 state.deaths = deaths
715
716 scoreValue.Text = tostring(score)
717 killsValue.Text = tostring(kills)
718 deathsValue.Text = tostring(deaths)
719
720 -- Pop animation for score
721 local popIn = TweenService:Create(scoreValue, TweenInfo.new(0.1, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {
722 TextSize = 26,
723 })
724 local popOut = TweenService:Create(scoreValue, TweenInfo.new(0.2, Enum.EasingStyle.Quad, Enum.EasingDirection.Out), {
725 TextSize = 22,
726 })
727 popIn:Play()
728 popIn.Completed:Connect(function()
729 popOut:Play()
730 end)
731end
732
733local function addKillFeedItem(killer, victim, weapon)
734 local item = createInstance("Frame", {
735 Name = "KillFeedItem",
736 Size = UDim2.fromOffset(260, 22),
737 BackgroundColor3 = CONFIG.BG_DARK,
738 BackgroundTransparency = 0.4,
739 BorderSizePixel = 0,
740 LayoutOrder = -(#state.killFeedItems),
741 ZIndex = 5,
742 Parent = killFeedContainer,
743 })
744 createCorner(item, 3)
745
746 local text = createInstance("TextLabel", {
747 Name = "KillFeedText",
748 Size = UDim2.new(1, -8, 1, 0),
749 Position = UDim2.fromOffset(4, 0),
750 BackgroundTransparency = 1,
751 Text = string.format("%s [X] %s", killer, victim),
752 TextColor3 = CONFIG.TEXT_WHITE,
753 TextSize = 12,
754 Font = Enum.Font.GothamBold,
755 TextXAlignment = Enum.TextXAlignment.Right,
756 ZIndex = 5,
757 Parent = item,
758 })
759
760 -- Entry animation
761 item.BackgroundTransparency = 1
762 text.TextTransparency = 1
763 local fadeIn = TweenService:Create(item, CONFIG.TWEEN_INFO_FAST, { BackgroundTransparency = 0.4 })
764 local textIn = TweenService:Create(text, CONFIG.TWEEN_INFO_FAST, { TextTransparency = 0 })
765 fadeIn:Play()
766 textIn:Play()
767
768 table.insert(state.killFeedItems, 1, item)
769
770 -- Remove after duration
771 task.delay(CONFIG.KILL_FEED_DURATION, function()
772 local fadeOut = TweenService:Create(item, CONFIG.TWEEN_INFO_NORMAL, {
773 BackgroundTransparency = 1,
774 })
775 local textOut = TweenService:Create(text, CONFIG.TWEEN_INFO_NORMAL, {
776 TextTransparency = 1,
777 })
778 fadeOut:Play()
779 textOut:Play()
780 fadeOut.Completed:Wait()
781 if item and item.Parent then
782 item:Destroy()
783 end
784 -- Remove from table
785 for i, v in ipairs(state.killFeedItems) do
786 if v == item then
787 table.remove(state.killFeedItems, i)
788 break
789 end
790 end
791 end)
792
793 -- Limit to 5 items
794 if #state.killFeedItems > 5 then
795 local old = table.remove(state.killFeedItems, 6)
796 if old and old.Parent then
797 old:Destroy()
798 end
799 end
800end
801
802local function showHitMarker()
803 hitMarker.Visible = true
804 for _, part in ipairs(hitParts) do
805 part.BackgroundTransparency = 0
806 end
807
808 -- Cancel existing timer
809 if state.hitMarkerTimer then
810 state.hitMarkerTimer:Disconnect()
811 end
812
813 -- Flash animation
814 for _, part in ipairs(hitParts) do
815 TweenService:Create(part, TweenInfo.new(0.05), {
816 BackgroundColor3 = CONFIG.CROSSHAIR_HIT_COLOR,
817 }):Play()
818 end
819
820 task.delay(0.05, function()
821 for _, part in ipairs(hitParts) do
822 TweenService:Create(part, TweenInfo.new(CONFIG.HITMARKER_DURATION), {
823 BackgroundColor3 = CONFIG.HITMARKER_COLOR,
824 BackgroundTransparency = 1,
825 }):Play()
826 end
827 end)
828
829 state.hitMarkerTimer = task.delay(CONFIG.HITMARKER_DURATION + 0.05, function()
830 hitMarker.Visible = false
831 state.hitMarkerTimer = nil
832 end)
833end
834
835local function showDamageIndicator(direction)
836 damageIndicator.Visible = true
837
838 local dirMap = { Top = 1, Bottom = 2, Left = 3, Right = 4 }
839 local index = dirMap[direction] or 1
840 local partData = damageParts[index]
841
842 if partData then
843 -- Flash the directional indicator
844 TweenService:Create(partData.frame, TweenInfo.new(0.1), {
845 BackgroundTransparency = 0.3,
846 }):Play()
847
848 task.delay(CONFIG.DAMAGE_INDICATOR_DURATION, function()
849 TweenService:Create(partData.frame, TweenInfo.new(0.3), {
850 BackgroundTransparency = 1,
851 }):Play()
852 end)
853 end
854
855 -- Hide container after all fade out
856 task.delay(CONFIG.DAMAGE_INDICATOR_DURATION + 0.4, function()
857 damageIndicator.Visible = false
858 end)
859end
860
861local function startReload(duration)
862 state.isReloading = true
863 reloadContainer.Visible = true
864 reloadBarFill.Size = UDim2.fromScale(0, 1)
865
866 local tween = TweenService:Create(reloadBarFill, TweenInfo.new(duration, Enum.EasingStyle.Linear), {
867 Size = UDim2.fromScale(1, 1),
868 })
869 tween:Play()
870
871 tween.Completed:Connect(function()
872 state.isReloading = false
873 reloadContainer.Visible = false
874 end)
875end
876
877local function switchWeapon(slot, weaponName)
878 state.currentWeapon = weaponName
879 weaponNameLabel.Text = string.upper(weaponName)
880
881 if slot == 1 then
882 TweenService:Create(slot1, CONFIG.TWEEN_INFO_FAST, {
883 BackgroundTransparency = 0.3,
884 TextColor3 = CONFIG.TEXT_WHITE,
885 }):Play()
886 TweenService:Create(slot2, CONFIG.TWEEN_INFO_FAST, {
887 BackgroundTransparency = 0.7,
888 TextColor3 = CONFIG.TEXT_GRAY,
889 }):Play()
890 elseif slot == 2 then
891 TweenService:Create(slot1, CONFIG.TWEEN_INFO_FAST, {
892 BackgroundTransparency = 0.7,
893 TextColor3 = CONFIG.TEXT_GRAY,
894 }):Play()
895 TweenService:Create(slot2, CONFIG.TWEEN_INFO_FAST, {
896 BackgroundTransparency = 0.3,
897 TextColor3 = CONFIG.TEXT_WHITE,
898 }):Play()
899 end
900end
901
902-- ============================================================
903-- CROSSHAIR DYNAMICS (Weapon sway and spread simulation)
904-- ============================================================
905
906local lastMousePos = Vector2.new(0, 0)
907local crosshairVelocity = Vector2.new(0, 0)
908local spreadScale = 0
909
910RunService.RenderStepped:Connect(function(deltaTime)
911 local mousePos = UserInputService:GetMouseLocation()
912 local delta = mousePos - lastMousePos
913 crosshairVelocity = crosshairVelocity:Lerp(delta, 0.3)
914 lastMousePos = mousePos
915
916 -- Increase crosshair gap based on movement speed
917 local speed = crosshairVelocity.Magnitude
918 local targetSpread = math.clamp(speed * 0.15, 0, 10)
919 spreadScale = spreadScale + (targetSpread - spreadScale) * 0.1
920
921 local gap = CONFIG.CROSSHAIR_GAP + spreadScale
922 local size = CONFIG.CROSSHAIR_SIZE
923
924 -- Update crosshair positions
925 chTop.Size = UDim2.fromOffset(CONFIG.CROSSHAIR_THICKNESS, size)
926 chTop.Position = UDim2.new(0.5, 0, 0, -gap)
927 chTop.AnchorPoint = Vector2.new(0.5, 1)
928
929 chBottom.Size = UDim2.fromOffset(CONFIG.CROSSHAIR_THICKNESS, size)
930 chBottom.Position = UDim2.new(0.5, 0, 1, gap)
931 chBottom.AnchorPoint = Vector2.new(0.5, 0)
932
933 chLeft.Size = UDim2.fromOffset(size, CONFIG.CROSSHAIR_THICKNESS)
934 chLeft.Position = UDim2.new(0, -gap, 0.5, 0)
935 chLeft.AnchorPoint = Vector2.new(1, 0.5)
936
937 chRight.Size = UDim2.fromOffset(size, CONFIG.CROSSHAIR_THICKNESS)
938 chRight.Position = UDim2.new(1, gap, 0.5, 0)
939 chRight.AnchorPoint = Vector2.new(0, 0.5)
940end)
941
942-- ============================================================
943-- REMOTE EVENT CONNECTIONS
944-- ============================================================
945
946updateHealthEvent.OnClientEvent:Connect(function(current, max)
947 updateHealth(current, max)
948end)
949
950updateAmmoEvent.OnClientEvent:Connect(function(current, reserve)
951 updateAmmo(current, reserve)
952end)
953
954updateScoreEvent.OnClientEvent:Connect(function(score, kills, deaths)
955 updateScore(score, kills, deaths)
956end)
957
958killFeedEvent.OnClientEvent:Connect(function(killer, victim, weapon)
959 addKillFeedItem(killer, victim, weapon)
960end)
961
962hitMarkerEvent.OnClientEvent:Connect(function()
963 showHitMarker()
964end)
965
966damageIndicatorEvent.OnClientEvent:Connect(function(direction)
967 showDamageIndicator(direction)
968end)
969
970reloadEvent.OnClientEvent:Connect(function(duration)
971 startReload(duration)
972end)
973
974weaponSwitchEvent.OnClientEvent:Connect(function(slot, weaponName)
975 switchWeapon(slot, weaponName)
976end)
977
978-- ============================================================
979-- KEYBOARD INPUT (Weapon switching)
980-- ============================================================
981
982UserInputService.InputBegan:Connect(function(input, gameProcessed)
983 if gameProcessed then return end
984
985 if input.KeyCode == Enum.KeyCode.One then
986 -- Fire to server to request weapon switch
987 local weaponRemote = remotes:WaitForChild("RequestWeaponSwitch")
988 weaponRemote:FireServer(1)
989 elseif input.KeyCode == Enum.KeyCode.Two then
990 local weaponRemote = remotes:WaitForChild("RequestWeaponSwitch")
991 weaponRemote:FireServer(2)
992 elseif input.KeyCode == Enum.KeyCode.R then
993 local reloadRemote = remotes:WaitForChild("RequestReload")
994 reloadRemote:FireServer()
995 end
996end)
997
998-- ============================================================
999-- INITIALIZATION - Demo sequence
1000-- ============================================================
1001
1002print("[FPS HUD] Initialized successfully")
1003
1004-- Show intro animation
1005task.spawn(function()
1006 -- Fade in all containers
1007 local containers = { healthContainer, ammoContainer, scoreContainer, weaponSlots }
1008 for _, container in ipairs(containers) do
1009 container.BackgroundTransparency = 1
1010 end
1011 for _, container in ipairs(containers) do
1012 TweenService:Create(container, CONFIG.TWEEN_INFO_SLOW, {
1013 BackgroundTransparency = 1,
1014 }):Play()
1015 task.wait(0.05)
1016 end
1017end)
1018
1019-- Demo: Simulate some kill feed entries after 2 seconds
1020task.delay(2, function()
1021 addKillFeedItem("PlayerOne", "Enemy_Soldier", "Rifle")
1022 task.wait(1.5)
1023 addKillFeedItem("SniperPro", "Enemy_Guard", "Sniper")
1024 task.wait(2)
1025 addKillFeedItem("You", "Enemy_Boss", "Rifle")
1026end)

Code preview

FPS HUD

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