In DevelopmentIndependent · 2026–Present

UI/UX Designer & Unreal Developer

Holdout is a survival-wave FPS built to demonstrate a complete game interface system in Unreal Engine 5. I designed, animated, and implemented the HUD, menus, and supporting gameplay systems.

Scroll
Overview

Holdout is a wave-survival first-person shooter I developed as an independent technical UI project. Its central focus is a complete HUD and menu system designed around a restrained night-operations visual language, reusable interface rules, motion, and a push-based connection between gameplay and UI.

I extended the gameplay with weapon swapping and a wave system so the interface could be implemented and tested against real state changes. Wave progress, enemies remaining, kills, health, ammunition, damage direction, countdowns, and fail-state statistics all update from their corresponding gameplay sources.

Alongside the UI, I adjusted the environment’s lighting and colour treatment to strengthen the mood and create a more cohesive visual experience. The project is still in development and brings together UX, visual design, motion, implementation, and interface engineering.

Role
UI/UX Designer & Unreal Developer
Tools
Unreal Engine 5 · Blueprint
Scope
HUD · Menus · Motion · Gameplay
Status
In Development · 2026–Present
The HUD and menu system respond to live gameplay states and events.
01

Design System

I created a compact token system to keep the HUD and eight menu screens visually consistent. Colour, typography, spacing, layout, components, and motion follow shared rules, with documented adjustments where text appears directly over gameplay.

Assigning one purpose to each colour

Teal identifies interactive, active, and positive states, while red communicates danger, damage, and failure. A neutral greyscale hierarchy separates primary values, labels, secondary information, panels, and backgrounds. Applying these meanings consistently helps players interpret the interface without relying on additional explanation.

Using one shared type system

Bahnschrift, uppercase styling, letter spacing, and a shared type scale create continuity from the title treatment to small HUD labels. I used the same colour-token values across the interface, then increased the brightness of teal and selected HUD labels where gameplay backgrounds required stronger contrast.

Design system · Zero Protocol
Consistent colour meaning · restrained military styling · live gameplay data
01 · Colour tokens
Teal
#4DA3A0
Interactive · good
Red
#C4536B
Danger · death
White
#D8DDE2
Primary values
Gray
#8A929C
Labels
Muted
#5F6771
Panel
#12161B
BG
#0F1216
Dark
#2A323B
02 · Type scale — Bahnschrift
HOLDOUT135 · Logo
YOU DIED90 · Hero
OPTIONS44 · Section title
[ 24 ] WAVE 0332 · HUD value
WAVE · RIFLE · NOVA_720 · HUD label
[ARROWS] NAVIGATE · [ENTER] SELECT13 · Nav hint
03 · Layout tokens
Menu button640 × 84
Overlay plate#0F1216 @ 82%
Plate rules2px teal
Cornershard / hairline
Anchoringedges → res-indep
04 · Motion
Ease-out, never linear, no bounce
e = 1 − (1 − t)²
Banner assembly5 beats
Hitmarker0.1s + fade
HUD boot-up0.09s stagger
One visual system applied across menus, components, motion, and the live HUD.
Component library
Reusable controls and consistent interaction states
Primary button
PLAY · focused
OPTIONS · default
Destructive button
QUIT · focused
QUIT · default
Slider
1.00
Filled track = teal · value readout live
Segmented selector
Low
Med
High
Epic
Active = teal border + teal label
Toggle
OnOff
Keycap
W A S DSPACEP
Teal identifies focus, red identifies destructive actions, and both remain consistent across screens.
The title screen uses teal for primary actions and red for destructive ones.
The title screen uses teal for primary actions and red for destructive ones.
The options screen applies the same tokens to sliders, toggles, and selectors.
The options screen applies the same tokens to sliders, toggles, and selectors.
02

HUD Architecture

I built the HUD around a push-based data flow rather than checking gameplay values every frame. Gameplay systems send updates only when a relevant state changes, allowing the interface to remain separate from the underlying mechanics without adding HUD Tick logic.

Updating UI only when state changes

The character, game mode, and projectile systems send state through a Blueprint interface on the player controller. The controller routes each update to corresponding Receive functions in the HUD widget, so values change in response to events rather than continuous polling.

Connecting each element to gameplay

Health updates through a Receive Health call, ammunition through Receive Bullets, and wave information through the game mode. Enemy deaths update the hostile counter and score, the damage arc rotates toward the attacker and fades over 1.2s, and the compass reads the controller’s current yaw.

HUD Data Sources
Each HUD element and the gameplay state that controls it
K/D counterTop left
Team score — pulses on every change
CompassTop centre
Reads live controller yaw
Wave + bannerTop right
Driven live from the game mode
Hostiles leftTop right
Decrements on the kill-hook, red flash
CrosshairCentre
Spreads on fire and move · hitmarker on hit
Damage arcCentre
Rotates toward the attacker, fades over 1.2s
Health + callsignBottom left
Lerps smoothly on ReceiveHealth
Ammo + weaponBottom right
Updates on ReceiveBullets
Interactive / status Danger NeutralPersistent information stays near the edges while temporary feedback appears near the centre.
The HUD displays live compass, wave, health, ammunition, and damage information.
The HUD displays live compass, wave, health, ammunition, and damage information.
03

Wave System

I created a state machine in the game mode to manage wave progression, enemy counts, escalation, and time between rounds. The same system also controls the interface states associated with starting, completing, and failing a wave.

Managing progression from one system

The wave manager tracks the current wave and number of enemies remaining, spawns increasingly difficult rounds, and controls the interval between them. I connected enemy deaths to the existing scoring event so one signal updates both the score and hostile counter.

Driving multiple interface states

The state machine controls the HUD wave counter, incoming-wave banner, between-wave countdown, and final wave statistic on the death screen. Because each interface state receives information from the same system, wave values remain consistent across gameplay and menus.

Gameplay and UI Loop
Each gameplay event triggers a corresponding interface response
Mechanic
Wave starts
spawn N enemies · N = base + escalation
UI reacts
Incoming banner + counter set
Mechanic
Combat
shoot · take damage · get hit
UI reacts
Hitmarker · health drain · damage arc · ammo
Mechanic
Enemy killed
kill-hook → score + counter decrement
UI reacts
Hostile count flash · K/D pulse
Mechanic
Wave cleared
count hits 0 · between-wave timer
UI reacts
Cleared overlay + live countdown
↺ loop · wave + 1, escalate
Fail state
Player dies
health reaches 0 · any wave
UI reacts
Game over · wave reached, K/D summary
Core loop   Fail stateOne gameplay state machine controls the core loop and its related UI states.
The death screen summarizes the final wave, kills, and deaths from live data.
The death screen summarizes the final wave, kills, and deaths from live data.
04

Motion Design

I developed a restrained motion language using short mechanical movements, firm stops, and no bounce or overshoot. A shared mathematical ease-out curve implemented in Blueprint gives banners, HUD feedback, menus, and transitions a consistent sense of timing.

Building motion through timed stages

The incoming-wave banner assembles through a sequence lasting approximately 0.4s. The background plate appears first, followed by the teal rules, the “INCOMING” label, and the wave number. Separating the motion into timed stages gives the announcement clearer hierarchy than a single fade.

Applying one timing system throughout

The same fast ease-out controls the HUD boot-up sequence, the hitmarker, the countdown emphasis, per-kill feedback, and menu transitions. Reusing the timing curve gives separate interface events a consistent visual rhythm while allowing their duration and scale to vary by purpose.

The pause overlay uses bracketed framing and the same restrained motion language.
The pause overlay uses bracketed framing and the same restrained motion language.
05

Design Decisions

Several design decisions came from testing the interface against changing gameplay conditions. These adjustments balanced readability, visual consistency, technical constraints, and the need to preserve visibility of the game world.

Maintaining legibility over gameplay

The HUD initially lost contrast over brighter parts of the arena. I tested an edge scrim, individual text shadows, and solid backing plates, then used plates for major overlays with corner vignettes and brighter labels for persistent HUD elements. This improved readability without covering important gameplay areas.

Adapting the world to the interface

I designed the directional damage indicator as a thin segmented bracket so it matched the interface’s existing geometry. I also shifted the original arena from bright orange lighting toward a desaturated night-operations palette, improving HUD contrast and creating a more cohesive relationship between the environment and interface.

The How to Play screen applies the same type, colour, and component rules.
The How to Play screen applies the same type, colour, and component rules.
Reflection

What I learned

Architecture shapes interface quality

Building the HUD around event-based updates showed me how strongly interface quality depends on architecture. Separating gameplay logic from presentation made the system easier to expand, while shared motion rules helped feedback remain purposeful rather than becoming visual decoration.

Documentation protects long-term consistency

Documenting colour, typography, layout, components, and motion made it easier to identify inconsistencies across the HUD and the eight menu screens. Recording intentional exceptions alongside the rules also prevented one-off adjustments from gradually weakening the broader visual language.

Rules sometimes require exceptions

Testing revealed situations where strict consistency reduced usability, particularly when interface elements appeared over gameplay. Brightening selected labels and adjusting the environment showed me that a design system should guide decisions while still allowing documented exceptions when context requires them.

Next Project

Feral