Web interfaces (NUI)
Resources can draw menus, HUDs and phones as web pages over the game. GAMPEON uses the same API as FiveM NUI, so most NUI resources work without changes.
A minimal menu
Section titled “A minimal menu”fx_version 'cerulean'ui_page 'html/index.html'client_script 'client.lua'files { 'html/app.js', 'html/style.css', 'html/img/*.png' }RegisterCommand('menu', function() SendNUIMessage({ type = 'open', items = { 'bread', 'water' } }) SetNuiFocus(true, true) -- keyboard and mouse go to the pageend)
RegisterNUICallback('close', function(data, cb) SetNuiFocus(false, false) cb('ok')end)window.addEventListener('message', (event) => { if (event.data.type === 'open') showMenu(event.data.items);});
function close() { fetch(`https://${GetParentResourceName()}/close`, { method: 'POST', body: JSON.stringify({ reason: 'button' }), });}How it works
Section titled “How it works”- Every resource with
ui_pagegets its own frame, transparent over the game. Pages of different resources do not see each other. ui_pageis sent to players with the other client files. List everything the page loads (scripts, styles, images, fonts) underfiles.- Pages load from
https://cfx-nui-<resource>/<path>, the same address as in FiveM. Onlyui_pageandfilesare served; client scripts and other files are not. SendNUIMessage(data)arrives asevent.dataof amessageevent. The data travels as JSON, at most 1 MB per message.fetch('https://<resource>/<name>')from the page calls the handler fromRegisterNUICallback(name, ...). The body is decoded from JSON and the value passed tocbcomes back as JSON.XMLHttpRequestworks the same way, so jQuery$.postand axios work too.- Messages sent before the page has loaded are delivered once it has loaded (up to 256).
- A page may also call callbacks and load files of other resources, as in FiveM, for example item images from
https://cfx-nui-<inventory>/…. - Resource names in these addresses are not case-sensitive, because browsers write host names in lower case. Callback addresses only work for resource names without a dot.
console.logand errors of pages appear in the game’s log as[client/nui].
Images and fonts from your game package
Section titled “Images and fonts from your game package”Graphics from store packs, such as UI sprites you bought for your own game, do not belong in a resource: every file under files is sent to every player as a plain file. Put them into your game package instead, in a folder Nui next to Content:
GamCity/ GamCity.uplugin Content/ Nui/ menus/panel_wide.png icons/coin.pngPages load them from https://gampeon-pkg-<package>/<path>, with the package name in lower case:
<img src="https://gampeon-pkg-gamcity/icons/coin.png" alt=""><div style="background-image: url('https://gampeon-pkg-gamcity/menus/panel_wide.png')"></div>- Only images (
png,jpg,webp,gif,avif), fonts (woff,woff2,ttf,otf), sounds (mp3,ogg,wav) and videos (mp4,webm) are served, at most 32 MB per file. Pages, scripts and styles stay in the resource. - Only packages the game has mounted are served. In the first stage that is every package given with
-gppackage=; later only the packages of the project the player joined. - The game log shows
Web interfaces (NUI): files of game package GamCity at https://gampeon-pkg-gamcity/when it works. - Free fonts under an open license (for example from Google Fonts) can stay in the resource.
Callbacks
Section titled “Callbacks”| Situation | The page gets |
|---|---|
The handler calls cb(value) |
Status 200 with value as JSON |
| The body is not JSON | 400 |
| No handler with that name | 404 |
| The body is larger than 64 KB | 413 |
| More than 256 requests are open | 429 |
| The handler fails with an error | 500 with { "error": "…" } |
| The resource stops before the answer | 503 |
| No answer within 30 seconds | 504 |
Handlers may call Wait before they answer.
-
SetNuiFocus(hasFocus, hasCursor)gives the keyboard and the mouse to the pages. The last call of any resource wins. -
SetNuiFocusKeepInput(true)lets the player keep moving while a page has focus. -
When the resource that set the focus stops, the focus goes back to the game.
-
Players can always take the focus back by holding Escape for 2 seconds, so a page cannot trap the mouse. A short press of Escape still reaches the page, so menus can close on Escape as usual.
-
The page stays visible after that. Your client script gets the event
gampeon:nuiFocusReleasedand can close its menu:AddEventHandler('gampeon:nuiFocusReleased', function(resourceName)if resourceName == GetCurrentResourceName() thenSendNUIMessage({ type = 'hide' })endend)
Test without the game
Section titled “Test without the game”With gampeon-server, join a fake player with gp_fakeplayer client <name> and then:
| Command | Effect |
|---|---|
gp_fakeplayer nui <id> <resource> <callback> [json] |
Calls the callback like fetch from the page and prints the answer |
gp_fakeplayer nuifile <id> <resource> <path> |
Loads a file like the browser does, or prints 404 |
gp_fakeplayer nuirelease <id> |
Takes the focus back like holding Escape in the game |
Messages, focus changes and answers appear as [client <id>/nui] in the output.
Compared to FiveM
Section titled “Compared to FiveM”- Same manifest entries, same functions, same
https://<resource>/<name>callbacks andGetParentResourceName(). - The low-level form
RegisterNuiCallbackTypewithAddEventHandler('__cfx_nui:name', ...)is not supported. UseRegisterNUICallback. ui_pagemust be a file of the resource. Remote pages (ui_page 'https://…') are not shown.- Pages run in a sandbox: no pop-ups, no
alert()orconfirm(), and they cannot navigate the game’s browser away. Images, fonts and scripts fromhttps://addresses still load, as in FiveM. - Pages on surfaces in the world (DUI) and loading screens (
loadscreen) come later.