Skip to content

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

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

RequirementDetail
PlatformFiveM (GTA V)
fx_versioncerulean
LuaLua 5.4 (lua54 'yes' — required for Asset Escrow)
Server artifact5181 or newer (Asset Escrow)
LicenseThe resource starts only on a server owned by the Tebex purchaser’s Keymaster account. Otherwise the console prints You lack the required entitlement.
FrameworkStandalone. 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 screensRun 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

  1. Copy this folder into your server resources directory.
    Recommended folder name: redeye_loadingscreen
  2. Start it before your framework / gameplay resources in server.cfg:
cfg
ensure redeye_loadingscreen
  1. Make sure no other resource sets loadscreen in its fxmanifest.lua.
  2. Restart the server, or from the console:
refresh
ensure redeye_loadingscreen
  1. Open config.lua, set Config.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 screen

The 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)

FlagValueMeaning
loadscreenhtml/index.htmlThis HTML file is the loading screen.
loadscreen_cursoryesPlayers can click Discord, mute, and the volume slider.
loadscreen_manual_shutdownyesFiveM 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:

  1. Server handover (server.lua)
    On playerConnecting, the server JSON-encodes Lang.payload() and passes it with deferrals.handover({ redeyeConfig = encoded }). The page reads window.nuiHandoverData. This is the fast path: the correct language and colors can appear immediately.

  2. Client messages (client.lua)
    After the client starts, SendLoadingScreenMessage sends { 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):

EventWhen
playerSpawnedThe player spawned in the world (works on standalone and most frameworks).
esx:loadingScreenOffESX 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:

eventNameTypical label (Config.Texts / locale)Behaviour
loadProgressloadingSets the target fraction (loadFraction).
initFunctionInvokingfunction name, or scriptsScript init; fraction from the event or current target.
startDataFileEntriesdataJumps the target to at least 0.12.
performMapLoadFunctionmapUses 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):

  1. Starts from English (Lang.Packs.en).
  2. Deep-merges the selected pack on top (arrays are replaced, not merged item-by-item).
  3. If Config.Locale is not a registered pack, it prints
    [redeye_loadingscreen] ismeretlen nyelv: <code> → en
    and uses English.

Lang.payload() then builds what the NUI receives:

FieldSource
Most of ConfigCopied as-is (Locale, ServerName, Show, Colors, Music, …).
TaglineConfig.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 / TextsConfig.* override if set; otherwise locale.
TickerIf Config.Ticker is set, that list is used as-is. If it is nil, the locale ticker is used and Config.ServerName is prepended.
LangCodeResolved 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.lua and set Config.Locale = 'xx' (the manifest already glob-loads locales/*.lua)
  • Per-element show/hide (Config.Show)
  • Per-effect on/off (Config.Effects)
  • Full colour palette (Config.Colors) — hex or rgba()
  • 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.

FileEditable
config.luayes
locales/*.luayes
html/img/* (logo)yes
html/audio/* (your music)yes
README.md, LICENSE.mdyes
client.lua, lang.lua, server.luano (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.

WhatWhereNotes
LanguageConfig.Locale'en' or 'hu', or your own pack key
Server nameConfig.ServerNameTop-left label; also prepended to the ticker when Config.Ticker is nil
TaglineConfig.TaglineSubtitle under the logo. nil → locale tagline
On-screen versionConfig.VersionDisplay only; a leading v is stripped. Independent from fxmanifest.lua version
Discord inviteConfig.DiscordReplace the placeholder or the button opens https://discord.gg/yourinvite
VolumeConfig.Volume0.01.0. Recommended 0.150.30. Default 0.22
Logohtml/img/logo.png + Config.LogoSee Logo
Musicfile in html/audio/ + Config.MusicSee Music
ColorsConfig.ColorsCSS variables on :root
Show / hide UIConfig.ShowSee UI visibility
EffectsConfig.EffectsSee 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>).

KeyWhat it hides/shows
tickerScrolling strip at the top
logoLogo image and the glow behind it
wordmarkLarge 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
hintRotating hint paragraph
rulesNumbered rules (01, 02, …)
keybindsKeybind grid
musicBottom player (title, artist, mute, visualizer, volume)
discordTop-right Discord button
versionVersion next to the server name
progressLabel, 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)

KeyEffect
blobsTwo blurred colour orbs in the background
logoFloatSlow up/down animation on the logo
logoGlowSoft red glow behind the logo
vizFour-bar visualizer next to the track title (CSS animation, not a real FFT)
lua
Config.Logo = {
    file      = 'img/logo.png', -- path relative to html/
    maxHeight = 48,             -- applied as CSS vh (48 → 48vh)
}
  • file is assigned to <img id="logo" src="…">. Keep the file under html/ and listed by the html/img/* glob in the manifest.
  • maxHeight is written to --logo-h as viewport height units (4848vh), matching the default in style.css. It is not pixels.

Colors (Config.Colors)

Each key maps to a CSS custom property:

Config keyCSS variableUsed for
bg--bgPage background
bg2--bg-2Secondary surfaces
red--redPrimary red
redHot--red-hotAccents, corners, wordmark “EYE”
ink--inkMain text
mute--muteSecondary text, ticker, version
line--lineHairline borders
glow--glowLogo glow and blobs
discord--discordDiscord 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:

KeyWhere it appears
discordDiscord button label
loadingDefault progress label
scriptsProgress label during script init (if the event has no name)
dataProgress label when data files start
mapProgress label during map load
no_musicTrack title if the audio file fails to load (artist line then shows html/audio/music.mp3)
  1. Replace html/img/logo.png, or add another image in html/img/ and set Config.Logo.file (path relative to html/, e.g. 'img/mylogo.webp').
  2. Tune size with Config.Logo.maxHeight (vh).
  3. 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.

  1. Place an audio file at html/audio/music.mp3 (MP3 is the usual choice; the <audio> element will play whatever the CEF build supports).
  2. Set Config.Music.file to that path relative to html/ (the glob html/audio/* already ships the folder).
  3. Set title and artist — these are labels only, not metadata from the file.
  4. Keep Config.Show.music = true to 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:

InputAction
Mute button (❚❚ / )Toggle mute (playback continues muted)
Volume slider0100; moving above 0 unmutes
SpaceToggle mute
Arrow UpVolume +5
Arrow DownVolume −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 key and label on each row.
  • Ticker items are joined with ·, duplicated so the CSS marquee (24s loop) stays filled. If you do not override Config.Ticker, ServerName is inserted at the front.

Adding a language

  1. Copy locales/en.lua to e.g. locales/de.lua.
  2. Change the key: Lang.Packs['de'] = { ... }.
  3. Translate every string.
  4. In config: Config.Locale = 'de'.

You do not edit fxmanifest.lualocales/*.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.md

Previewing 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

SymptomWhat to check
You lack the required entitlementServer Keymaster account is not the Tebex buyer. Artifact too old (< 5181).
Default English UI / wrong coloursConfig.Locale typo; handover failed (see console [redeye_loadingscreen] handover failed:); ensure ensure redeye_loadingscreen is in server.cfg.
Screen never closesAnother resource fighting the loadscreen; playerSpawned never fires (custom spawn). ESX servers should still get esx:loadingScreenOff. Do not remove loadscreen_manual_shutdown.
Two loading screensA second resource also declares loadscreen.
Discord opens the placeholderSet Config.Discord to your invite.
No music / “No music” titleFile missing, wrong Config.Music.file, or format not supported. Path is relative to html/ (audio/music.mp3html/audio/music.mp3).
Music blocked until clickNormal CEF autoplay policy; first click or Space starts it.
Logo missingFile not in html/img/, or Config.Logo.file path wrong.
Cursor missing, cannot clickloadscreen_cursor 'yes' must stay in the manifest.
Unknown locale warningConfig.Locale does not match any Lang.Packs['…'] key.
Changes not applyingRestart the resource (ensure redeye_loadingscreen). Clients already on the loading screen already received the old payload — reconnect.

Notes

  • Config.Version is only the label on the loading screen, not the resource version in fxmanifest.lua.
  • The HTML wordmark is the RedEye brand (RED + EYE), not a dynamic server name. Config.ServerName is the top-left text.
  • Do not run two loadscreen resources.
  • Support is for the original Tebex purchaser. See LICENSE.md.