Appearance
RedEye Loading Screen
FiveM loading screen — logo, music player, ticker, rules, keybinds, and a full config.
Version: 1.1.0
This resource is protected by Cfx.re Asset Escrow (Tebex).
Contents
- What this resource does
- Requirements
- Installation
- How it works
- Features
- Asset Escrow
- Quick setup
config.luareference- Logo
- Music
- Texts (locale files)
- File structure
- Previewing in a browser
- Troubleshooting
- Notes
What this resource does
redeye_loadingscreen replaces the default FiveM loading screen with a branded NUI page (html/index.html). While the game, scripts, data files and map are loading, players see:
- server name and on-screen version in the top bar
- Discord invite button (opens the URL with the in-game cursor)
- logo (or an optional RedEye wordmark)
- tagline and rotating hints
- numbered rules list
- keybind grid
- a progress bar driven by FiveM’s built-in loadscreen events
- a looping music player with volume slider, mute, and a visualizer
- a scrolling ticker at the top
- background blobs, corner frames, logo float and glow (all optional)
All texts, colors, visibility toggles and assets are meant to be edited in open files: config.lua, locales/*.lua, html/img/ and html/audio/. Encrypted Lua only wires the config into the page and shuts the screen down when the player is in.
Requirements
| Requirement | Detail |
|---|---|
| Platform | FiveM (GTA V) |
fx_version | cerulean |
| Lua | Lua 5.4 (lua54 'yes' — required for Asset Escrow) |
| Server artifact | 5181 or newer (Asset Escrow) |
| License | The resource starts only on a server owned by the Tebex purchaser’s Keymaster account. Otherwise the console prints You lack the required entitlement. |
| Framework | Standalone. ESX is optional: if ESX fires esx:loadingScreenOff, the screen also closes. QBCore / other frameworks work as long as the player eventually spawns (playerSpawned). |
| Other loading screens | Run only one loading screen resource. Disable or remove any other loadscreen resource from server.cfg. |
Internet is used once at load time for the Outfit Google Font. If the client cannot reach Google Fonts, the UI still works with the system fallback font.
Installation
- Copy this folder into your server
resourcesdirectory.
Recommended folder name:redeye_loadingscreen - Start it before your framework / gameplay resources in
server.cfg:
cfg
ensure redeye_loadingscreen- Make sure no other resource sets
loadscreenin itsfxmanifest.lua. - Restart the server, or from the console:
refresh
ensure redeye_loadingscreen- Open
config.lua, setConfig.Locale,Config.ServerName,Config.Discord, and (optionally) add your logo and music. See Quick setup.
Typical server.cfg order
cfg
ensure redeye_loadingscreen
ensure es_extended # or your framework — after the loading screenThe loading screen does not depend on ESX. Putting it first only ensures the NUI page is registered before players connect.
How it works
The screen is a FiveM NUI loadscreen, not a regular UI that you open with a command.
Manifest flags (fxmanifest.lua)
| Flag | Value | Meaning |
|---|---|---|
loadscreen | html/index.html | This HTML file is the loading screen. |
loadscreen_cursor | yes | Players can click Discord, mute, and the volume slider. |
loadscreen_manual_shutdown | yes | FiveM will not close the screen by itself. Lua must call ShutdownLoadingScreen / ShutdownLoadingScreenNui. |
Config delivery (two paths)
The NUI page needs the merged config (colors, texts, music path, etc.). It is sent in two ways so the first paint is not empty:
Server handover (
server.lua)
OnplayerConnecting, the server JSON-encodesLang.payload()and passes it withdeferrals.handover({ redeyeConfig = encoded }). The page readswindow.nuiHandoverData. This is the fast path: the correct language and colors can appear immediately.Client messages (
client.lua)
After the client starts,SendLoadingScreenMessagesends{ eventName = 'config', config = Lang.payload() }up to 40 times, every 250 ms. If handover was missed or late, this still applies the live config.
If neither arrives in time (~1 second), html/js/app.js falls back to a built-in English default object (same defaults as config.lua / locales/en.lua).
Shutdown
client.lua closes the screen once, then ignores further events (closed flag):
| Event | When |
|---|---|
playerSpawned | The player spawned in the world (works on standalone and most frameworks). |
esx:loadingScreenOff | ESX finished its own loading flow. |
Both call ShutdownLoadingScreen() and ShutdownLoadingScreenNui().
Progress bar
The page listens to FiveM loadscreen NUI messages and maps them to the bar label + percentage:
eventName | Typical label (Config.Texts / locale) | Behaviour |
|---|---|---|
loadProgress | loading | Sets the target fraction (loadFraction). |
initFunctionInvoking | function name, or scripts | Script init; fraction from the event or current target. |
startDataFileEntries | data | Jumps the target to at least 0.12. |
performMapLoadFunction | map | Uses loadFraction, or 0.55 if missing. |
The fill is smoothed in requestAnimationFrame (it eases toward the target, never jumps backward). Percentage text updates only when the rounded value changes.
Language merge (lang.lua)
Lang.resolve(Config.Locale):
- Starts from English (
Lang.Packs.en). - Deep-merges the selected pack on top (arrays are replaced, not merged item-by-item).
- If
Config.Localeis not a registered pack, it prints[redeye_loadingscreen] ismeretlen nyelv: <code> → en
and uses English.
Lang.payload() then builds what the NUI receives:
| Field | Source |
|---|---|
Most of Config | Copied as-is (Locale, ServerName, Show, Colors, Music, …). |
Tagline | Config.Tagline if set; otherwise locale tagline. An empty string '' is kept (Lua treats '' as set). Use nil if you want the locale tagline. |
Hints / Rules / Keybinds / Texts | Config.* override if set; otherwise locale. |
Ticker | If Config.Ticker is set, that list is used as-is. If it is nil, the locale ticker is used and Config.ServerName is prepended. |
LangCode | Resolved language code (hu, en, …). Sets <html lang>. |
Features
- Hungarian and English out of the box (
locales/hu.lua,locales/en.lua) - Extra locale files: drop
locales/xx.luaand setConfig.Locale = 'xx'(the manifest already glob-loadslocales/*.lua) - Per-element show/hide (
Config.Show) - Per-effect on/off (
Config.Effects) - Full colour palette (
Config.Colors) — hex orrgba() - Optional background music (you add your own file; nothing is bundled)
- In-page music controls: mute button, volume slider, Space / Arrow keys
- Rules, hints, keybinds, ticker from locale or config overrides
- ESX-compatible shutdown (
esx:loadingScreenOff) - Cfx.re Asset Escrow (Tebex)
No music file is included. Add your own legally usable track if you want audio.
Asset Escrow
Lua that ships encrypted: client.lua, lang.lua, server.lua.
Buyers may edit the files listed in escrow_ignore inside fxmanifest.lua.
| File | Editable |
|---|---|
config.lua | yes |
locales/*.lua | yes |
html/img/* (logo) | yes |
html/audio/* (your music) | yes |
README.md, LICENSE.md | yes |
client.lua, lang.lua, server.lua | no (escrow) |
The loading screen HTML/CSS/JS is NUI: Cfx.re does not encrypt it. You can restyle html/css/style.css or html/index.html, but the supported way to brand the screen is still config.lua + locales + logo/music. Advanced HTML edits are at your own risk (updates will overwrite them).
Quick setup
Open config.lua. Every option has English and Hungarian comments.
| What | Where | Notes |
|---|---|---|
| Language | Config.Locale | 'en' or 'hu', or your own pack key |
| Server name | Config.ServerName | Top-left label; also prepended to the ticker when Config.Ticker is nil |
| Tagline | Config.Tagline | Subtitle under the logo. nil → locale tagline |
| On-screen version | Config.Version | Display only; a leading v is stripped. Independent from fxmanifest.lua version |
| Discord invite | Config.Discord | Replace the placeholder or the button opens https://discord.gg/yourinvite |
| Volume | Config.Volume | 0.0–1.0. Recommended 0.15–0.30. Default 0.22 |
| Logo | html/img/logo.png + Config.Logo | See Logo |
| Music | file in html/audio/ + Config.Music | See Music |
| Colors | Config.Colors | CSS variables on :root |
| Show / hide UI | Config.Show | See UI visibility |
| Effects | Config.Effects | See Visual effects |
config.lua reference
Config.Locale
String key matching Lang.Packs['…'] in a locale file. Unknown values fall back to English with a console warning.
Config.ServerName
Shown as the strong label in the top-left header (#serverName). Used as ticker prefix when you do not set Config.Ticker.
Config.Tagline
Subtitle under the logo (#tagline).
Config.Version
Shown next to the server name. The UI strips a leading v / V (so 'v1.0.0' becomes 1.0.0). This is not the resource version in fxmanifest.lua (1.1.0).
Config.Discord
Full URL. Click uses invokeNative('openUrl', url) in FiveM, or window.open if you preview the HTML in a browser.
Config.Volume
Initial <audio> volume and slider position (volume * 100). Players can change it live; that does not write back to config.lua.
UI visibility (Config.Show)
true = shown, false = hidden (CSS class on <body>).
| Key | What it hides/shows |
|---|---|
ticker | Scrolling strip at the top |
logo | Logo image and the glow behind it |
wordmark | Large RED****EYE text logo in the centre (html/index.html — not Config.ServerName). Default false. Enable if you want the wordmark; usually you hide the image logo when using it |
hint | Rotating hint paragraph |
rules | Numbered rules (01, 02, …) |
keybinds | Keybind grid |
music | Bottom player (title, artist, mute, visualizer, volume) |
discord | Top-right Discord button |
version | Version next to the server name |
progress | Label, percent, and bar |
Hiding music only hides the player UI. To fully skip audio, also omit the file or leave Config.Show.music = false so players are not looking for a missing track.
Visual effects (Config.Effects)
| Key | Effect |
|---|---|
blobs | Two blurred colour orbs in the background |
logoFloat | Slow up/down animation on the logo |
logoGlow | Soft red glow behind the logo |
viz | Four-bar visualizer next to the track title (CSS animation, not a real FFT) |
Logo (Config.Logo)
lua
Config.Logo = {
file = 'img/logo.png', -- path relative to html/
maxHeight = 48, -- applied as CSS vh (48 → 48vh)
}fileis assigned to<img id="logo" src="…">. Keep the file underhtml/and listed by thehtml/img/*glob in the manifest.maxHeightis written to--logo-has viewport height units (48→48vh), matching the default instyle.css. It is not pixels.
Colors (Config.Colors)
Each key maps to a CSS custom property:
| Config key | CSS variable | Used for |
|---|---|---|
bg | --bg | Page background |
bg2 | --bg-2 | Secondary surfaces |
red | --red | Primary red |
redHot | --red-hot | Accents, corners, wordmark “EYE” |
ink | --ink | Main text |
mute | --mute | Secondary text, ticker, version |
line | --line | Hairline borders |
glow | --glow | Logo glow and blobs |
discord | --discord | Discord button background |
Hex (#RRGGBB) and rgba() are both valid.
Music (Config.Music)
lua
Config.Music = {
file = 'audio/music.mp3',
title = 'Your track',
artist = 'Your artist',
}See Music.
Optional overrides
Uncomment at the bottom of config.lua to ignore the locale for that field:
lua
Config.Hints = { 'Custom hint' }
Config.Rules = { 'Custom rule' }
Config.Keybinds = { { key = 'F1', label = 'Phone' } }
Config.Ticker = { 'RedEye', 'Los Santos' }
Config.Texts = {
discord = 'Discord',
loading = 'Loading',
scripts = 'Scripts',
data = 'Data',
map = 'Map',
no_music = 'No music',
}If these stay unset (nil), locale values are used.
Config.Texts keys:
| Key | Where it appears |
|---|---|
discord | Discord button label |
loading | Default progress label |
scripts | Progress label during script init (if the event has no name) |
data | Progress label when data files start |
map | Progress label during map load |
no_music | Track title if the audio file fails to load (artist line then shows html/audio/music.mp3) |
Logo
- Replace
html/img/logo.png, or add another image inhtml/img/and setConfig.Logo.file(path relative tohtml/, e.g.'img/mylogo.webp'). - Tune size with
Config.Logo.maxHeight(vh). - PNG with transparency works best on the dark background.
fxmanifest.lua already includes html/img/*. New files in that folder do not need a manifest edit.
To show only the centre wordmark: Config.Show.logo = false and Config.Show.wordmark = true.
Music (optional)
This pack does not ship a music file. You must add your own, legally usable track.
- Place an audio file at
html/audio/music.mp3(MP3 is the usual choice; the<audio>element will play whatever the CEF build supports). - Set
Config.Music.fileto that path relative tohtml/(the globhtml/audio/*already ships the folder). - Set
titleandartist— these are labels only, not metadata from the file. - Keep
Config.Show.music = trueto show the player.
The track loops. Autoplay is attempted on config apply; if the browser blocks it, the first click anywhere on the page starts playback.
To run without music: Config.Show.music = false. You can leave Config.Music as-is.
If the file is missing or invalid, the player shows texts.no_music as the title.
Music controls (in-game)
The loadscreen cursor is enabled, so these work during load:
| Input | Action |
|---|---|
Mute button (❚❚ / ▶) | Toggle mute (playback continues muted) |
| Volume slider | 0–100; moving above 0 unmutes |
| Space | Toggle mute |
| Arrow Up | Volume +5 |
| Arrow Down | Volume −5 |
Texts (locale files)
Hints, rules, keybinds, ticker, tagline and button labels come from:
- English:
locales/en.lua - Hungarian:
locales/hu.lua
lua
Config.Locale = 'en' -- or 'hu'Each pack is a table assigned to Lang.Packs['code']:
lua
Lang = Lang or { Packs = {} }
Lang.Packs['en'] = {
tagline = 'Los Santos Roleplay',
texts = { discord = 'Discord', loading = 'Loading', ... },
hints = { '…', '…' },
rules = { '…', '…' },
keybinds = {
{ key = 'F1', label = 'Phone' },
-- …
},
ticker = { 'Los Santos', 'Roleplay', 'Scripts' },
}- Hints rotate every 5.6 seconds with a short fade. Order is the array order. One item is fine; an empty list keeps the fallback English hints in JS only if config never arrived.
- Rules are rendered as a list with a two-digit index (
01,02, …). - Keybinds need
keyandlabelon each row. - Ticker items are joined with
·, duplicated so the CSS marquee (24sloop) stays filled. If you do not overrideConfig.Ticker,ServerNameis inserted at the front.
Adding a language
- Copy
locales/en.luato e.g.locales/de.lua. - Change the key:
Lang.Packs['de'] = { ... }. - Translate every string.
- In config:
Config.Locale = 'de'.
You do not edit fxmanifest.lua — locales/*.lua is already loaded as a shared script.
Missing keys in a new pack fall back to English because packs are merged onto Lang.Packs.en.
Overrides in config
To force custom texts (ignoring locale), uncomment the examples at the bottom of config.lua. If those keys stay nil, locale values are used.
Ticker override note: if you set Config.Ticker yourself, ServerName is not auto-prepended. Add it to the list if you still want it.
File structure
redeye_loadingscreen/
├── fxmanifest.lua resource manifest, loadscreen flags, escrow_ignore
├── config.lua server branding (open / escrow_ignore)
├── lang.lua locale resolver + payload (escrow)
├── client.lua NUI config spam + shutdown (escrow)
├── server.lua connecting handover (escrow)
├── locales/
│ ├── en.lua
│ └── hu.lua
├── html/
│ ├── index.html NUI document
│ ├── css/style.css
│ ├── js/app.js config apply, progress, music, keys
│ ├── img/logo.png
│ └── audio/ put your own music.mp3 here
├── README.md
└── LICENSE.mdPreviewing in a browser
You can open html/index.html in a desktop browser to check layout. Without FiveM:
- handover/config messages never arrive → JS fallback English defaults are used
- Discord uses
window.open - progress stays at 0% unless you simulate
window.postMessage - autoplay rules depend on the browser
This is useful for CSS tweaks, not for testing locale/config.
Troubleshooting
| Symptom | What to check |
|---|---|
You lack the required entitlement | Server Keymaster account is not the Tebex buyer. Artifact too old (< 5181). |
| Default English UI / wrong colours | Config.Locale typo; handover failed (see console [redeye_loadingscreen] handover failed:); ensure ensure redeye_loadingscreen is in server.cfg. |
| Screen never closes | Another resource fighting the loadscreen; playerSpawned never fires (custom spawn). ESX servers should still get esx:loadingScreenOff. Do not remove loadscreen_manual_shutdown. |
| Two loading screens | A second resource also declares loadscreen. |
| Discord opens the placeholder | Set Config.Discord to your invite. |
| No music / “No music” title | File missing, wrong Config.Music.file, or format not supported. Path is relative to html/ (audio/music.mp3 → html/audio/music.mp3). |
| Music blocked until click | Normal CEF autoplay policy; first click or Space starts it. |
| Logo missing | File not in html/img/, or Config.Logo.file path wrong. |
| Cursor missing, cannot click | loadscreen_cursor 'yes' must stay in the manifest. |
| Unknown locale warning | Config.Locale does not match any Lang.Packs['…'] key. |
| Changes not applying | Restart the resource (ensure redeye_loadingscreen). Clients already on the loading screen already received the old payload — reconnect. |
Notes
Config.Versionis only the label on the loading screen, not the resource version infxmanifest.lua.- The HTML wordmark is the RedEye brand (
RED+EYE), not a dynamic server name.Config.ServerNameis the top-left text. - Do not run two loadscreen resources.
- Support is for the original Tebex purchaser. See
LICENSE.md.
