games / fivem
NUI : interface HTML/JS embarquée
Explication
Ce que vous allez apprendre
- Comprendre ce qu'est la NUI et pourquoi c'est une vraie page web classique
- Déclarer une page NUI dans le
fxmanifest.lua(ui_page,files) - Envoyer des données du Lua vers le JavaScript avec
SendNUIMessage - Recevoir ces données côté JavaScript via
window.addEventListener('message', ...) - Donner le contrôle du curseur/clavier au joueur avec
SetNuiFocus
Dans quel contexte ?
Un serveur RP veut proposer un menu de boutique avec des articles cliquables, des images et une mise en page soignée — quelque chose que les éléments d'interface natifs du jeu ne permettent tout simplement pas de construire facilement. La NUI répond exactement à ce besoin en embarquant un vrai moteur de navigateur web par-dessus le jeu, avec toutes les compétences HTML/CSS/JS habituelles directement réutilisables.
| Élément du manifest | Rôle |
|---|---|
ui_page 'html/ui.html' | Déclare la page NUI de la ressource |
files { ... } | Rend les fichiers web accessibles au moteur NUI |
Piège fréquent
Oublier SetNuiFocus(true, true) après avoir affiché une interface NUI laisse le joueur incapable de cliquer ou de taper dans cette interface, tout en continuant de contrôler son personnage normalement : l'UI est visible mais totalement inutilisable, un oubli très courant chez les débutants.
Sortir des limites du jeu lui-même
Le moteur de GTA V sait dessiner des éléments d'interface basiques (texte, jauges), mais reste très limité pour construire des interfaces modernes comme un menu de boutique avec des boutons cliquables, des listes déroulantes ou des animations fluides. FiveM contourne cette limite en embarquant un véritable moteur de navigateur web (basé sur la même technologie que Chrome), ce qui permet à n'importe quelle ressource d'afficher sa propre page web par-dessus le jeu. C'est ce qu'on appelle la NUI (New/Native User Interface).
Une vraie page web, avec ses propres règles
C'est le point essentiel à intégrer : une interface NUI, ce n'est ni plus ni moins qu'une page HTML/CSS/JavaScript classique, comme n'importe quel site web. Toutes les compétences de développement web habituelles s'appliquent directement — mise en page CSS, manipulation du DOM en JavaScript. La seule vraie nouveauté est la façon dont cette page communique avec le code Lua du jeu.
Lua parle à JavaScript : SendNUIMessage
Le Lua ne peut pas manipuler directement les éléments de la page web. Il envoie plutôt un message structuré (SendNUIMessage) que la page JavaScript reçoit via un mécanisme standard du navigateur (window.addEventListener('message', ...)), et c'est le JavaScript qui se charge ensuite de mettre à jour l'affichage en fonction de ce message reçu.
Rendre le contrôle au joueur
Par défaut, la page NUI est invisible et ne capte ni le clavier ni la souris : le joueur continue de contrôler son personnage normalement. SetNuiFocus(true, true) doit être appelé explicitement pour "donner" le curseur et le clavier à l'interface — un oubli fréquent chez les débutants, qui se retrouvent avec une interface visible mais totalement impossible à utiliser.
Commandes & code
NUI : interface HTML/CSS/JS embarquée
FiveM embarque un moteur CEF (type Chromium) : chaque ressource peut afficher sa propre page web par-dessus le jeu.
-- fxmanifest.lua (rappel de la leçon 2)
ui_page 'html/ui.html'
files {
'html/ui.html',
'html/ui.js',
'html/ui.css',
}<!-- html/ui.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="ui.css">
</head>
<body>
<div id="shop" class="hidden">
<h2>Boutique</h2>
<ul id="shop-items"></ul>
<button id="close-btn">Fermer</button>
</div>
<script src="ui.js"></script>
</body>
</html>/* html/ui.css */
.hidden {
display: none;
}
#shop {
position: absolute;
top: 20%;
left: 50%;
transform: translateX(-50%);
width: 320px;
background: rgba(20, 20, 20, 0.9);
color: white;
border-radius: 8px;
padding: 16px;
font-family: sans-serif;
}-- CLIENT (client/nui.lua) : ouvrir l'interface et lui envoyer des données
local function OpenShopMenu()
SetNuiFocus(true, true) -- (hasFocus, hasCursor) : rend le curseur/clavier à la page NUI
SendNUIMessage({
action = 'openShop',
items = {
{ name = 'bread', price = 5 },
{ name = 'water', price = 3 },
}
})
end
RegisterNetEvent('technologik:openShop', OpenShopMenu)// html/ui.js : réception des messages envoyés par Lua via SendNUIMessage
window.addEventListener('message', (event) => {
const data = event.data;
if (data.action === 'openShop') {
const shop = document.getElementById('shop');
const list = document.getElementById('shop-items');
list.innerHTML = '';
data.items.forEach(item => {
const li = document.createElement('li');
li.textContent = `${item.name} - $${item.price}`;
list.appendChild(li);
});
shop.classList.remove('hidden');
}
});Résumé
ui_page+filesdans le manifest exposent la page au moteur NUI.SendNUIMessage(Lua → JS) envoie des données viawindow.addEventListener('message', ...).SetNuiFocus(true, true)est indispensable pour que le joueur puisse cliquer/taper dans l'UI.
Exercices pratiques
Mission : le menu boutique figé à l'écran
Objectif : Corriger une interface NUI visible mais totalement inutilisable, puis raisonner sur la synchronisation entre chargement de page et envoi de messages.
Contexte
Un joueur signale que le menu de boutique s'affiche bien à l'écran après avoir tapé /shop, mais qu'il est impossible de cliquer sur quoi que ce soit ni de bouger la souris pour interagir : le personnage continue de courir normalement pendant ce temps. Le code client de la commande /shop se limite à SendNUIMessage({ action = 'openShop', items = items }), sans rien d'autre.