Loading screensbeginner15 min readupdated 11 Sept 2026

Build your own FiveM loading screen from scratch

The short answer

Create a resource folder with fxmanifest.lua (declaring loadscreen 'index.html', loadscreen_cursor 'yes' and all files under files), an index.html with a background, logo, progress bar and audio element, a style.css using viewport units and object-fit: cover, and a script.js that listens for loadProgress and onLogLine messages. Add ensure for it, disable any other loading screen and restart.

You can build a good loading screen with nothing but a text editor: one manifest, one HTML file, one stylesheet and one script. This tutorial builds a complete one — responsive background, logo, a real progress bar, a status line, music with a mute button and a personal greeting — and explains each part so you can change it afterwards.

Build your own FiveM loading screen from scratch — illustrated with a FiveM-compatible minimap render

#The folder

resources/[ui]/my_loadscreen/
my_loadscreen/
├── fxmanifest.lua
├── index.html
├── style.css
├── script.js
├── img/
│   ├── bg.webp
│   └── logo.png
└── music/
    └── theme.mp3

#Step 1: fxmanifest.lua

fxmanifest.lua
fx_version 'cerulean'
game 'gta5'

name 'my_loadscreen'
description 'Custom loading screen'

loadscreen 'index.html'
loadscreen_cursor 'yes'

files {
    'index.html',
    'style.css',
    'script.js',
    'img/*',
    'music/*',
}

Each directive is explained in the loading screen manifest guide.

#Step 2: index.html

index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <img class="bg" src="img/bg.webp" alt="">
  <div class="shade"></div>

  <main class="safe">
    <img class="logo" src="img/logo.png" alt="My City">
    <p class="welcome" id="welcome">Welcome to My City</p>

    <div class="bar"><div class="fill" id="fill"></div></div>
    <p class="status" id="status">Connecting…</p>
  </main>

  <button class="mute" id="mute" aria-label="Mute music">🔊</button>
  <audio id="music" src="music/theme.mp3" autoplay loop></audio>

  <script src="script.js"></script>
</body>
</html>

#Step 3: style.css

style.css
html, body { margin: 0; height: 100%; overflow: hidden; background: #05070d; font-family: system-ui, sans-serif; color: #fff; }

.bg { position: fixed; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.shade { position: fixed; inset: 0; background: linear-gradient(180deg, rgba(5,7,13,.15), rgba(5,7,13,.8)); }

.safe {
  position: fixed; inset: 0; margin: auto;
  width: min(100vw, calc(100vh * 16 / 9)); aspect-ratio: 16 / 9;
  display: flex; flex-direction: column; align-items: center; justify-content: flex-end;
  gap: 1.6vh; padding-bottom: 9vh; box-sizing: border-box;
}
.logo { width: clamp(180px, 20vw, 560px); height: auto; margin-bottom: auto; margin-top: 18vh; }
.welcome { font-size: clamp(16px, 1.3vw, 28px); opacity: .9; margin: 0; }
.bar { width: min(560px, 60vw); height: 6px; border-radius: 99px; background: rgba(255,255,255,.15); overflow: hidden; }
.fill { height: 100%; width: 0; background: #5b6af0; transition: width .4s ease; }
.status { font-size: clamp(12px, .85vw, 18px); opacity: .7; margin: 0; }

.mute { position: fixed; right: 2vw; bottom: 2vw; width: 44px; height: 44px; border-radius: 12px; border: 1px solid rgba(255,255,255,.2); background: rgba(0,0,0,.4); color: #fff; font-size: 18px; cursor: pointer; }

Viewport units and a 16:9 safe area keep this correct on every resolution — the reasoning is in responsive loading screens.

#Step 4: script.js

script.js
const fill = document.getElementById('fill');
const status = document.getElementById('status');
const music = document.getElementById('music');
const mute = document.getElementById('mute');
let shown = 0;

// Greeting from the server, if it sends one (deferrals.handover)
const hand = window.nuiHandoverData || {};
if (hand.name) document.getElementById('welcome').textContent = `Welcome, ${hand.name}`;

// Loading events from FiveM
window.addEventListener('message', (e) => {
  const d = e.data || {};
  if (d.eventName === 'loadProgress') {
    shown = Math.max(shown, Math.min(1, d.loadFraction));
    fill.style.width = (shown * 100).toFixed(1) + '%';
  }
  if (d.eventName === 'onLogLine') status.textContent = d.message;
});

// Music: gentle volume, remembered mute
music.volume = 0.3;
music.muted = localStorage.getItem('muted') === '1';
mute.textContent = music.muted ? '🔇' : '🔊';
mute.addEventListener('click', () => {
  music.muted = !music.muted;
  localStorage.setItem('muted', music.muted ? '1' : '0');
  mute.textContent = music.muted ? '🔇' : '🔊';
});

#Step 5: install and test

  1. Open index.html in Chrome or Edge and check the layout at a few window sizes.
  2. Put the folder in resources/ and add ensure my_loadscreen to server.cfg.
  3. Disable any other loading screen resource (qb-loadingscreen, esx_loadingscreen or similar) — only one may declare loadscreen.
  4. Restart the server and connect.

#Where to take it next

Share this guideXRedditFacebook

Questions

How do I make my own FiveM loading screen?
Create a resource with a manifest that declares loadscreen 'index.html' and lists every file under files, write the HTML, CSS and JavaScript, then ensure it and disable any other loading screen.
Do I need to know JavaScript?
Only a little: the script in this tutorial is enough for a progress bar, status line and music. Everything else is HTML and CSS.
Why does my loading screen show but images are missing?
The image files are not listed under files in the manifest, so the client never downloads them.
Can I test the loading screen without FiveM?
Yes, open index.html in a desktop browser. Only the loading events need the game; you can fake them from the console.

Ready to pick a map?

Twelve themes on three base map styles, $8 each, instant download.

The tool for this

A drag-and-drop loading screen, hosted for you From Free, built in the browser, exported as a drop-in resource.

Look it up while you work

The reference tables this guide leans on, free and without an account.