Applied Module 12 · The Lora Playbook

The HUD and Inventory Builder

What you'll learn

~55 min
  • Build a Phaser HUD with health bar, blood rage meter, and ammo indicator
  • Implement a 4x4 inventory grid with pickup items and keyboard toggle
  • Create a pause screen with player stats and resume functionality
  • Add a minimap placeholder that frames future level integration

What you’re building

Your combat loop works. Enemies take damage, the player dodges, particles fly. But right now the player has no idea how much health they have left, whether their rage meter is full, or what they picked up three rooms ago. The game feels like a tech demo because it is missing the layer that turns mechanics into readable gameplay: the HUD.

BloodRayne had one of the better HUDs of its era. Rayne’s health was literally blood — she healed by feeding on enemies, so the health bar pulsed and drained in a way that made you feel the vampire fantasy. She had a rage meter that filled during combat and unleashed a devastating mode when full. Dual blades and guns meant you needed weapon indicators. Your remake needs the same information density without the same screen clutter.

Forty minutes from now you will have a full HUD overlay with a blood-themed health bar, a rage meter, an ammo/weapon indicator, pickup items that populate a toggleable 4x4 inventory grid, a pause screen with stats, and a minimap placeholder ready for level data.

Software pattern: UI overlay system with state binding

HUD elements bound to game state variables, rendered as a separate Phaser scene layered on top of gameplay. This pattern — a persistent UI layer that reads from shared state — is identical to dashboards, status bars, and notification systems in any application.


The showcase

Here is what the finished HUD system gives you:

  • Blood health bar: Top-left, red-to-dark gradient that drains left-to-right. Pulses gently when below 30%. Fills back up when the player “feeds” (placeholder mechanic tied to a key press for now).
  • Blood rage meter: Below the health bar, a purple bar that fills as the player deals damage. When full, the border glows and the player can activate rage mode (R key) for a temporary damage boost.
  • Weapon indicator: Bottom-left icon showing current weapon (blade or gun) with ammo count for guns. Switch weapons with Q.
  • Pickup items: Collectible objects placed in the scene. Walking over them adds them to inventory with a brief flash notification.
  • Inventory grid: Press I to toggle a 4x4 grid overlay. Items show as colored icons with names on hover. Click an item to “use” it (restores health, fills rage, etc.).
  • Pause screen: Press ESC to pause. Dark overlay with player stats (health, rage, items collected, enemies defeated, time played). Press ESC again or click Resume to continue.
  • Minimap placeholder: Top-right corner, a small bordered rectangle showing a static grid. This is a frame that will display actual room layouts once level data exists from L17.

The prompt

Open your terminal, navigate to your game project folder, start your AI CLI tool, and paste this prompt:

Build a Phaser 3 HUD and inventory system as a separate scene that overlays
the gameplay scene. The game is a BloodRayne-inspired action game with
vampire mechanics.
PROJECT STRUCTURE:
hud-inventory/
package.json
index.html
src/
main.js (Phaser game config, launches both scenes)
GameScene.js (simple gameplay scene with a player, 3 enemies, 5 pickups)
HUDScene.js (HUD overlay scene - health, rage, weapon, minimap)
InventoryScene.js (inventory grid overlay - toggled with I key)
PauseScene.js (pause overlay - toggled with ESC)
state.js (shared game state object)
REQUIREMENTS:
1. SHARED STATE (src/state.js)
Export a single object that all scenes read/write:
- health: 100 (max 100)
- maxHealth: 100
- rage: 0 (max 100)
- maxRage: 100
- rageActive: false
- currentWeapon: 'blade' (or 'gun')
- ammo: 30
- maxAmmo: 30
- inventory: [] (array of item objects, max 16 slots = 4x4 grid)
- enemiesDefeated: 0
- itemsCollected: 0
- timeStarted: null (set when game begins)
- paused: false
2. GAME SCENE (src/GameScene.js)
Simple gameplay scene for testing the HUD:
- 800x600 canvas, dark background (#18181b)
- Player: 32x32 purple rectangle (#8B5CF6), WASD movement at 200px/s
- 3 enemies: 24x24 red rectangles (#ef4444), stationary
- 5 pickup items scattered around: colored circles (16px diameter)
- Red potion (restores 25 health)
- Purple crystal (adds 30 rage)
- Ammo box (yellow, restores 15 ammo)
- Shield shard (blue, placeholder item)
- Key fragment (green, placeholder item)
- Collisions:
- Player + enemy: reduce health by 10, knock player back, brief invincibility
- Player + pickup: add to inventory, remove from scene, flash notification
- Combat keys:
- SPACE: attack (if blade, melee range; if gun, reduce ammo by 1)
- R: activate rage mode when rage >= 100 (2x damage for 5 seconds, drains rage)
- Q: switch weapon (blade/gun toggle)
- F: feed on nearby enemy (must be within 40px, restores 20 health, adds 10 rage)
- Damage dealt adds 5 rage per hit
- Launch HUDScene as a parallel scene on create
3. HUD SCENE (src/HUDScene.js)
Rendered on top of GameScene, ignores game world camera:
a. HEALTH BAR (top-left, x:16 y:16)
- Background: dark rectangle 200x20, border 1px #333
- Fill: gradient left-to-right, #dc2626 to #7f1d1d
- Width scales with state.health / state.maxHealth
- When health < 30: bar pulses (alpha oscillates 0.6-1.0, 500ms cycle)
- Label: "BLOOD" in small white text above the bar
b. RAGE METER (below health bar, x:16 y:48)
- Background: dark rectangle 200x14, border 1px #333
- Fill: #8B5CF6 (purple), width scales with state.rage / state.maxRage
- When rage == 100: border color changes to #a78bfa, gentle glow pulse
- When rageActive: bar drains visually, border flashes gold #f59e0b
- Label: "RAGE" in small white text above
c. WEAPON INDICATOR (bottom-left, x:16 y:560)
- Icon: small rectangle, purple for blade, yellow for gun
- Text: weapon name + ammo count for gun ("GUN 24/30") or "BLADE"
- Ammo text turns red when ammo < 5
d. MINIMAP PLACEHOLDER (top-right, x:680 y:16)
- 104x104 bordered rectangle (#333 border, #111 fill)
- Static 5x5 grid of light lines inside (representing rooms)
- Small green dot representing player position (center for now)
- Label: "MAP" in small white text above
e. NOTIFICATION AREA (top-center, x:400 y:80)
- When a pickup is collected, show item name in white text
- Fade in, hold 1.5 seconds, fade out
- Queue multiple notifications if they overlap
f. Update every frame by reading from the shared state object
4. INVENTORY SCENE (src/InventoryScene.js)
Toggled with I key (starts hidden):
a. OVERLAY
- Semi-transparent black background (alpha 0.85)
- Centered panel: 320x320 with border #8B5CF6
- Title: "INVENTORY" in white, centered at top of panel
b. GRID
- 4x4 grid of 64x64 cells with 1px #333 borders
- Each cell shows the item's colored circle icon (same color as pickup)
- Item name text below the icon, small font
- Empty cells show a subtle "—" placeholder
- Hover: cell border highlights to #8B5CF6
c. ITEM USE
- Click an item cell to "use" it:
- Red potion: restore 25 health (cap at max), remove from inventory
- Purple crystal: add 30 rage (cap at max), remove from inventory
- Ammo box: restore 15 ammo (cap at max), remove from inventory
- Shield shard / key fragment: show "Cannot use yet" message
- Brief flash effect on use
d. CONTROLS
- I key: close inventory (toggle off)
- Inventory is NOT available during pause
5. PAUSE SCENE (src/PauseScene.js)
Toggled with ESC key:
a. OVERLAY
- Semi-transparent black background (alpha 0.9)
- Centered panel: 400x300 with border #8B5CF6
b. STATS DISPLAY
- Title: "PAUSED" in large white text
- Health: current/max
- Rage: current/max
- Weapon: current weapon + ammo
- Items collected: count
- Enemies defeated: count
- Time played: MM:SS format (calculated from state.timeStarted)
c. CONTROLS
- "RESUME" text button (click or press ESC to unpause)
- When paused: GameScene physics paused, HUD still visible but dimmed
DEPENDENCIES: phaser (^3.80), vite
Add "dev" script in package.json: "vite"
Background color for the HTML page: #09090b
💡Copy-paste ready

That prompt is specific about every pixel position, color, and interaction because HUD work is where vague prompts produce the most rework. Every “put it roughly in the corner” turns into three follow-up prompts adjusting positions. Spell it out once, get it right once.


What you get

After the AI finishes generating (typically 60-90 seconds), you will have:

hud-inventory/
package.json
index.html
src/
main.js
GameScene.js
HUDScene.js
InventoryScene.js
PauseScene.js
state.js

Fire it up

Terminal window
cd hud-inventory
npm install
npm run dev

Open the URL (usually http://localhost:5173). You should see the gameplay scene with a purple player square, red enemies, and colored pickup circles. The HUD is already live in the top-left corner — health bar, rage meter, weapon indicator, and minimap placeholder.

Walk into an enemy to see health drain. Hit SPACE to attack and watch rage build. Press F near an enemy to feed and restore health. Collect pickups by walking over them. Press I to open inventory. Press ESC to pause.

If something is off

ProblemFollow-up prompt
HUD elements move with the game cameraThe HUD scene should have its own camera that ignores the game world. Make sure HUDScene sets this.cameras.main.setScroll(0, 0) and does not follow the player. HUD elements should use fixed screen coordinates, not world coordinates.
Inventory grid items are invisibleItems are being added to state.inventory but the inventory grid shows empty cells. Make sure InventoryScene reads state.inventory on each toggle (re-render the grid every time I is pressed) and maps each item's type to the correct color and label.
Pause does not stop gameplayWhen ESC is pressed, the pause overlay appears but enemies still move and the player still takes damage. Add this.scene.pause('GameScene') when pausing and this.scene.resume('GameScene') when unpausing.
Rage mode does not activatePressing R when rage is 100 does nothing. Make sure the R key listener in GameScene checks state.rage >= state.maxRage, sets state.rageActive = true, and starts a 5-second timer that drains rage to 0 and sets rageActive back to false.

Deep dive

The architecture here is the most important thing to understand, because it applies far beyond games.

Separate scenes for UI layers. Phaser lets you run multiple scenes simultaneously. The GameScene handles gameplay logic and physics. The HUDScene runs on top, reading from shared state every frame, but with its own camera that never scrolls. This is the same pattern as a dashboard overlay on any application — the data source and the display layer are decoupled.

Shared state as the single source of truth. The state.js module exports one object. GameScene writes to it (health changes, items collected). HUDScene reads from it (bar widths, numbers). InventoryScene reads and writes (using items removes them). PauseScene reads (stats display). Nobody passes data directly between scenes. This is a simple version of state management that scales cleanly.

Why a 4x4 grid? Sixteen slots is enough to be interesting without requiring scroll or pagination logic. It matches classic action game inventories — Resident Evil 4 used a grid, Diablo used a grid, BloodRayne’s inventory was simpler but the concept is the same. If you need more slots later, change one number in the grid renderer.

The minimap is intentionally a placeholder. It draws a static grid with a green dot. That is all it needs to be right now. In L17 you will build a level editor that exports room layouts as JSON. When that data exists, the minimap will render actual room shapes. Building the frame now means the integration later is a single prompt, not a redesign.

🔍BloodRayne's blood health mechanic

In the original BloodRayne (2002), Rayne’s primary healing mechanic was feeding on enemies. She would grab a Nazi soldier, bite their neck, and drain their blood to restore her health. This created a risk-reward loop: you had to get close to enemies to heal, which meant exposing yourself to damage. The blood rage meter built during combat and unleashed a devastating aura attack. Your HUD captures both mechanics — the pulsing health bar at low health creates urgency (“I need to feed”), and the rage meter filling during combat creates anticipation (“almost ready for rage mode”). These are not just UI elements. They are feedback loops that drive player behavior.


Customize it

Add a combo counter

Add a combo counter to the HUD. When the player hits enemies in rapid
succession (within 2 seconds of each hit), increment a combo counter
displayed in large text at the top-center of the screen. The counter
resets if 2 seconds pass without a hit. At combo 5+, the text turns
yellow. At combo 10+, it turns orange and shakes. Combos above 5
add bonus rage (2 extra rage per hit per combo level).

Add an equipment slot system

Add 3 equipment slots below the inventory grid: Head, Body, Accessory.
Items with type "equipment" can be dragged from inventory to an
equipment slot. Equipped items provide passive bonuses displayed as
stat modifiers: +10 max health, +20 max rage, -1 damage taken. Show
equipped items as highlighted in the inventory grid.

Try it yourself

  1. Paste the main prompt and let the AI generate the project.
  2. Run npm install && npm run dev and test every interaction: take damage, feed, collect items, open inventory, use a potion, activate rage, pause and check stats.
  3. Intentionally let your health drop below 30% and watch the health bar pulse. That visual feedback is what makes the vampire fantasy feel real.
  4. Open inventory and use items. Verify they disappear from the grid and the effect applies.
  5. Check the minimap placeholder. It is just a frame right now — and that is correct. The level editor in L17 will fill it.

Key takeaways

  • UI layers as separate scenes keep HUD logic cleanly separated from gameplay logic. No tangled update functions.
  • Shared state is the bridge between scenes. One object, multiple readers, clean data flow.
  • Blood-themed health is not just aesthetic — the pulsing bar at low health creates urgency that drives the core feed mechanic.
  • Placeholders are architecture. The minimap frame exists now so the level editor integration later is trivial.
  • Keyboard shortcuts (I, ESC, Q, R, F) must be deliberate and non-conflicting. Document them in the pause screen so the player always has a reference.
💡This is the player's window into your game

A HUD that reads well is the difference between a prototype that feels like a game and a prototype that feels like a tech demo. Rayne’s blood health bar told a story — “I’m a vampire, I need to feed.” Your HUD should do the same. Every element is a sentence in the conversation between your game and the player.


What’s next

Your player can see their health, manage their inventory, and pause the game. But the game world is still silent — there is no story, no objectives, no sense of progress. In the next lesson you will build a dialogue and objective system that gives the player mission briefings, NPC interactions, branching choices, and a save/load system. That is the layer that turns a combat sandbox into something with narrative direction.