Économisez 20 % avec WELCOMEVoir les promotions
Écran de chargement de FiveM

Comment créer un écran de chargement FiveM personnalisé

D'accord, examinons la création d'un point d'entrée unique et engageant pour vos joueurs.

Nous allons construire un Écran de chargement FiveM personnalisé à partir de la base.

Qu'est-ce qu'une ressource d'écran de chargement ?

Un écran de chargement personnalisé est souvent la toute première interaction d'un joueur avec votre serveur FiveM spécifique.

C'est une fantastique opportunité pour établir la marque de votre serveur, transmettre des informations importantes et créer une atmosphère détaillée dès le début.

Oubliez les visuels génériques de FiveM ; nous voulons que les joueurs se sentent ton l'identité du serveur au moment où ils commencent à se connecter.

Ici chez FiveMX, nous croyons en donnant aux propriétaires de serveurs les outils et les connaissances pour créer des configurations de roleplay vraiment spécifiques.

Ce guide complet vous accompagnera à chaque étape, de la structure HTML de base à la mise en forme avec CSS, en passant par l'ajout d'interactivité avec JavaScript, et enfin son intégration documentée dans votre serveur FiveM à l'aide de Lua.

Nous expliquerons même comment masquer cette animation de pont FiveM par défaut pour une transition plus nette.

Commençons à faire en sorte que votre serveur se différencie de la configuration.

Pourquoi s'embêter avec un écran de chargement FiveM personnalisé ?

Vous vous demandez peut-être si cela en vaut la peine.

Absolument!

Considérez-le comme le hall d’entrée ou l’entrée de votre monde virtuel.

Premières impressions : Il donne immédiatement le ton et le professionnalisme de votre serveur.

Image de marque : Renforcez le nom, le logo et le thème général de votre serveur.

Affichage des informations : Partagez des informations cruciales telles que des règles, des liens Discord, des URL de sites Web ou des mises à jour de l'état du serveur avant les joueurs apparaissent même.

Fiançailles: Utilisez de la musique, des messages dynamiques ou même des vidéos pour garder les joueurs engagés pendant le processus de chargement, réduisant ainsi les temps d'attente perçus.

Unicité: Différenciez votre serveur des innombrables autres en utilisant des écrans par défaut ou génériques.

Un écran de chargement bien conçu montre que vous vous souciez des détails et de l'expérience du joueur.

Prérequis

Avant de commencer à coder, assurons-nous que vous disposez des outils nécessaires et des connaissances de base :

  1. Éditeur de texte : Vous aurez besoin d’un programme pour écrire votre code.
    • Visual Studio Code (VS Code) : gratuit, puissant et fortement recommandé, avec de nombreuses extensions utiles.
    • Sublime Text : une autre option populaire et légère.
    • Notepad++ : un choix gratuit solide pour les utilisateurs de Windows.
    • Éviter en utilisant le Bloc-notes ou TextEdit de base, car ils manquent de fonctionnalités utiles pour le codage (comme la coloration syntaxique).
  2. Connaissances de base en développement Web (utiles, pas essentielles) :
    • HTML (langage de balisage hypertexte) : Comprend la structure de base d'une page Web (balises telles que <div>, <img>, <p>). Nous fournirons le code, mais connaître les bases aide.
    • CSS (feuilles de style en cascade) : Savoir styliser les éléments HTML (couleurs, tailles, positions). Nous vous guiderons, mais une certaine connaissance est un plus.
    • JavaScript (JS) : Comprendre les concepts de base de la programmation pour ajouter de l'interactivité. Nous allons d'abord privilégier un code JavaScript relativement simple.
  3. Accès au serveur FiveM : Vous avez besoin d'accéder aux fichiers de votre serveur, en particulier aux ressources dossier, pour installer l'écran de chargement.
  4. Logiciel de retouche d'image (facultatif) : Des outils comme Photoshop, GIMP (gratuit) ou même Canva peuvent être utiles pour créer ou éditer des logos et des images d'arrière-plan.
  5. Patience et volonté d'apprendre : Le débogage et le réglage font partie du processus !

Ne vous inquiétez pas si vous n’êtes pas un expert en développement Web.

Nous expliquerons clairement chaque étape et fournirons des extraits de code copiables-collables.

Comprendre le fonctionnement des écrans de chargement de FiveM (NUI)

FiveM utilise un système appelé NUI (interface utilisateur native) pour afficher des pages Web à l'intérieur le jeu.

Essentiellement, votre écran de chargement personnalisé n'est qu'une page Web standard (construite avec HTML, CSS et JavaScript) que le système NUI de FiveM restitue pendant que les ressources du jeu se chargent en arrière-plan.

Cela signifie que nous pouvons exploiter les technologies Web standard pour créer des expériences visuellement riches et interactives.

Le cœur les composants sont :

  • index.html: Le fichier principal définissant la structure et le contenu de votre écran de chargement.
  • style.css: Le fichier qui définit l'apparence visuelle (mise en page, couleurs, polices, etc.).
  • script.js: Le fichier qui ajoute un comportement dynamique (comme la modification du texte, des animations, la lecture de musique).
  • fxmanifest.lua (ou __ressource.lua): Un fichier FiveM spécial qui indique au serveur qu'il s'agit d'une ressource, spécifie qu'il s'agit d'un écran de chargement et répertorie tous les fichiers nécessaires.

Maintenant, commençons à construire.

Étape 1 : Création de la structure HTML de base (index.html)

Commencez par créer un nouveau dossier pour votre ressource d'écran de chargement. Appelons-le mon-écran-de-chargement.

Dans ce dossier, créez un fichier nommé index.html.

Ce fichier contiendra le squelette de notre écran de chargement.

Nous avons besoin de conteneurs pour différents éléments : l'arrière-plan, un logo, une indication de progression du chargement et des zones pour les messages texte.

<!DOCTYPE html>
<html lang="en">
<head>
 <meta charset="UTF-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
 <title>Nom du serveur - Chargement...</title>
 <!-- Link to your CSS file -->
 <link rel="stylesheet" href="style.css">
</head>
<body>

 <!-- Main container for the entire screen -->
 <div class="loading-container">

 <!-- Background Element (handled by CSS) -->
 <div class="background"></div>

 <!-- Content Wrapper -->
 <div class="content">

 <!-- Logo Area -->
 <div class="logo-area">
 <img src="images/logo.png" alt="Logo du serveur" id="server-logo">
 <!-- You can replace img with text if you prefer -->
 <!-- <h1>My Awesome Server</h1> -->
 </div>

 <!-- Message Area -->
 <div class="message-area">
 <p id="loading-message">Initialisation de la connexion...</p>
 <p id="dynamic-message">Bienvenue ! Chargement des ressources du serveur…</p>
 </div>

 <!-- Progress Bar Area -->
 <div class="progress-bar-container">
 <div class="progress-bar">
 <div class="progress-bar-inner" id="progress-bar-inner"></div>
 </div>
 <p id="progress-text">0%</p>
 </div>

 <!-- Music Control (Optional) -->
 <div class="music-control">
 <button id="play-pause-button">Pause Musique</button>
 <input type="range" id="volume-slider" min="0" max="1" step="0.01" value="0.5">
 </div>

 </div> <!-- End Content Wrapper -->

 </div> <!-- End Loading Container -->

 <!-- Link to your JavaScript file (place at the end of body) -->
 <script src="script.js"></script>
</body>
</html>

Explication:

  • & <html>: Modèle HTML5 standard.
  • : Contient des méta-informations et des liens vers des ressources externes.
    • charset="UTF-8": Assure un affichage correct des caractères.
    • fenêtre d'affichage:Important pour la conception réactive (s'adaptant à différentes tailles d'écran), bien que moins critique pour les écrans de chargement de jeux à résolution fixe.
    • </code>: Définit le texte qui peut apparaître dans un onglet de navigateur (moins pertinent dans FiveM NUI mais bonne pratique).</li> <li><code></code>:Connecte notre HTML à notre fichier CSS pour le style.</li> </ul> </li> <li><strong><code><body></code>:</strong> Contient le contenu visible de la page.</li> <li><strong><code><div class="loading-container"></code>:</strong> L'enveloppe principale pour tout. Nous l'utiliserons pour la mise en page générale.</li> <li><strong><code><div class="background"></code>:</strong> Un div vide que nous styliserons avec CSS pour contenir notre image d'arrière-plan ou notre vidéo.</li> <li><strong><code><div class="content"></code>:</strong> Enveloppe le contenu réel (logo, texte, barre de progression) pour faciliter le centrage et le positionnement.</li> <li><strong><code><div class="logo-area"></code>:</strong> Un conteneur pour le logo de votre serveur. <ul class="wp-block-list"> <li><code><img src="images/logo.png" ...></code>:Une balise d'image. <strong>Important:</strong> Vous devrez créer un <code>images</code> dossier à l'intérieur <code>mon-écran-de-chargement</code> et placez votre <code>logo.png</code> fichier là-bas. Assurez-vous que le nom du fichier correspond !</li> </ul> </li> <li><strong><code><div class="message-area"></code>:</strong> Contient des messages texte. <ul class="wp-block-list"> <li>Nous donnons des identifiants aux paragraphes (<code>message de chargement</code>, <code>message dynamique</code>) afin que nous puissions facilement les cibler avec JavaScript plus tard.</li> </ul> </li> <li><strong><code><div class="progress-bar-container"></code>:</strong> Contient les éléments de la barre de progression. <ul class="wp-block-list"> <li><code>.barre de progression</code>:Le contenant extérieur de la barre.</li> <li><code>.barre de progression intérieure</code>: La partie intérieure qui va se remplir. On lui donne un identifiant (<code>barre de progression intérieure</code>) pour le contrôle JS.</li> <li><code><p id="progress-text"></code>: Affiche le texte en pourcentage, également avec un ID.</li> </ul> </li> <li><strong><code><div class="music-control"></code>:</strong> (Facultatif) Contrôles de base pour la musique de fond. Les identifiants permettent l'interaction JS.</li> <li><strong><code></code>:</strong> Relie notre HTML à notre fichier JavaScript. En le plaçant à la fin du <code><body></code> garantit que les éléments HTML existent avant que le script tente d'interagir avec eux.</li> </ul> <p class="wp-block-paragraph">Enregistrer ce fichier sous <code>index.html</code> dans ton <code>mon-écran-de-chargement</code> dossier. Créer un <code>images</code> sous-dossier et ajouter un espace réservé <code>logo.png</code> pour l'instant.</p> <h2 class="wp-block-heading" id="step-2-styling-the-loading-screen-css-style-css">Étape 2 : Style de l’écran de chargement (CSS – <code>style.css</code>)</h2> <p class="wp-block-paragraph">Maintenant, faisons en sorte que ça soit beau !</p> <p class="wp-block-paragraph">Créez un fichier nommé <code>style.css</code> dans le même <code>mon-écran-de-chargement</code> dossier.</p> <p class="wp-block-paragraph">Ce fichier contrôle la présentation visuelle.</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">/* Basic Reset & Body Styling */ * { margin: 0; padding: 0; box-sizing: border-box; /* Makes width/height include padding and border */ } body, html { height: 100%; width: 100%; overflow: hidden; /* Hide scrollbars */ font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; /* Example font */ color: #ffffff; /* Default text color (white) */ } /* Main Container */ .loading-container { position: relative; /* Needed for absolute positioning of children */ width: 100%; height: 100%; display: flex; /* Use flexbox for centering content */ justify-content: center; align-items: center; text-align: center; } /* Background Styling */ .background { position: absolute; /* Take up full screen behind content */ top: 0; left: 0; width: 100%; height: 100%; background-image: url('images/background.jpg'); /* CHANGE THIS to your image */ background-size: cover; /* Scale image to cover the container */ background-position: center center; /* Center the image */ background-repeat: no-repeat; z-index: -1; /* Place it behind other content */ filter: brightness(0.6); /* Optional: Darken the background slightly */ } /* --- OR Use a Solid Color Background --- */ /* .background { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: #1a1a1a; z-index: -1; } */ /* Content Wrapper */ .content { z-index: 1; /* Ensure content is above the background */ padding: 20px; background-color: rgba(0, 0, 0, 0.5); /* Semi-transparent black background */ border-radius: 10px; max-width: 600px; /* Limit content width */ box-shadow: 0 4px 15px rgba(0, 0, 0, 0.4); } /* Logo Area */ .logo-area { margin-bottom: 30px; } #server-logo { max-width: 200px; /* Adjust max logo width */ height: auto; /* Maintain aspect ratio */ display: block; /* Allows margin auto to center */ margin-left: auto; margin-right: auto; } /* Message Area */ .message-area { margin-bottom: 30px; } #loading-message { font-size: 1.2em; font-weight: bold; margin-bottom: 10px; color: #cccccc; } #dynamic-message { font-size: 1em; min-height: 40px; /* Prevent layout shifts when message changes */ } /* Progress Bar Area */ .progress-bar-container { width: 80%; /* Width relative to the content container */ margin: 0 auto; /* Center the container */ margin-bottom: 20px; } .progress-bar { width: 100%; background-color: #555555; /* Dark grey background */ border-radius: 5px; overflow: hidden; /* Hide overflowing inner bar */ height: 25px; /* Bar height */ border: 1px solid #333; } .progress-bar-inner { height: 100%; width: 0%; /* Start at 0% width */ background-color: #4CAF50; /* Green progress color */ border-radius: 5px 0 0 5px; /* Keep left radius */ transition: width 0.5s ease-in-out; /* Smooth transition for width changes */ text-align: center; line-height: 25px; /* Vertically center text if needed inside */ color: white; } #progress-text { margin-top: 5px; font-size: 0.9em; } /* Music Control (Optional) */ .music-control { margin-top: 25px; display: flex; /* Arrange button and slider side-by-side */ justify-content: center; align-items: center; gap: 15px; /* Space between elements */ } #play-pause-button { padding: 8px 15px; background-color: #4CAF50; color: white; border: none; border-radius: 5px; cursor: pointer; font-size: 0.9em; transition: background-color 0.3s ease; } #play-pause-button:hover { background-color: #45a049; } #volume-slider { cursor: pointer; width: 150px; /* Adjust slider width */ } /* Add some basic responsiveness if needed, though less critical in NUI */ @media (max-width: 600px) { .content { max-width: 90%; } .progress-bar-container { width: 90%; } }</pre> <p class="wp-block-paragraph"><strong>Explication:</strong></p> <ul class="wp-block-list"> <li><strong><code>* { taille-de-la-boîte : boîte-de-bordure ; }</code></strong>:Une réinitialisation commune pour rendre les éléments de dimensionnement plus prévisibles.</li> <li><strong><code>corps, html</code></strong>: Définit la hauteur/largeur de base et masque les éventuelles barres de défilement. Définit une police et une couleur de texte par défaut.</li> <li><strong><code>.conteneur de chargement</code></strong>: Utilisations <code>affichage : flex</code> pour centrer facilement le <code>.contenu</code> div les deux horizontalement (<code>justifier le contenu</code>) et verticalement (<code>aligner-les-éléments</code>). <code>position : relative</code> est crucial pour positionner l'arrière-plan absolu.</li> <li><strong><code>.arrière-plan</code></strong>: <ul class="wp-block-list"> <li><code>position : absolue</code>:Sort l'élément du flux normal et le positionne par rapport à l'ancêtre positionné le plus proche (<code>.conteneur de chargement</code>).</li> <li><code>haut : 0 ; gauche : 0 ; largeur : 100% ; hauteur : 100% ;</code>: Il recouvre l'intégralité du conteneur.</li> <li><code>image d'arrière-plan : url(...)</code>: <strong>Le changement est crucial <code>'images/background.jpg'</code> au chemin réel de votre image d'arrière-plan.</strong> Assurez-vous que l'image est dans le <code>images</code> dossier.</li> <li><code>taille de l'arrière-plan : couverture</code>:Met l'image à l'échelle.</li> <li><code>z-index: -1</code>:Le pousse derrière d'autres éléments.</li> <li><code>filtre : luminosité (0,6)</code>: Un effet optionnel pour assombrir l'arrière-plan et rendre le texte plus lisible. Ajustez ou supprimez-le selon vos besoins.</li> <li><em>Alternative:</em> Une section commentée montre comment utiliser une simple couleur d'arrière-plan unie au lieu d'une image.</li> </ul> </li> <li><strong><code>.contenu</code></strong>: <ul class="wp-block-list"> <li><code>z-index: 1</code>:Assure qu'il se trouve au-dessus de l'arrière-plan.</li> <li><code>couleur d'arrière-plan : rgba(0, 0, 0, 0,5)</code>: Un fond noir semi-transparent pour la zone de contenu elle-même, aidant le texte à se différencier du fond complexe. Ajustez la dernière valeur (alpha) de 0 (complètement transparent) à 1 (complètement opaque).</li> <li><code>rayon de bordure</code>, <code>largeur maximale</code>, <code>boîte-ombre</code>:Ajoutez une touche de finition visuelle.</li> </ul> </li> <li><strong><code>.zone-logo</code>, <code>Logo du serveur #</code></strong>: Stylise le conteneur du logo et l'image du logo elle-même (définition de la largeur maximale, centrage).</li> <li><strong><code>.zone de message</code>, <code>#chargement-message</code>, <code>#message dynamique</code></strong>: Stylise les éléments de texte (taille de police, couleur, marges). <code>hauteur minimale</code> empêche la mise en page de sauter lorsque le contenu du message dynamique change de longueur.</li> <li><strong><code>.conteneur de barre de progression</code>, <code>.barre de progression</code>, <code>.barre de progression intérieure</code></strong>: Stylise la barre de progression. <ul class="wp-block-list"> <li>Le récipient extérieur (<code>.barre de progression</code>) définit la couleur et la forme de l'arrière-plan.</li> <li>La barre intérieure (<code>.barre de progression intérieure</code>) est ce qui grandit. Cela commence à <code>largeur : 0%</code>Nous allons modifier cette largeur en utilisant JavaScript. <code>transition : largeur 0,5 s entrée-sortie en douceur ;</code> rend le changement de largeur fluide.</li> </ul> </li> <li><strong><code>.contrôle de la musique</code>, <code>#bouton lecture-pause</code>, <code>Curseur de volume #</code></strong>: Stylise les commandes musicales facultatives à l'aide de flexbox pour la mise en page et ajoute un style de bouton de base.</li> <li><strong><code>@media (largeur maximale : 600 px)</code></strong>: Exemple simple de requête média pour la réactivité. Elle ajuste la largeur du contenu sur les écrans plus petits (moins critique pour FiveM, mais bonne pratique).</li> </ul> <p class="wp-block-paragraph">Enregistrer sous <code>style.css</code>. N'oubliez pas de créer le <code>images</code> dossier et ajoutez votre <code>fond.jpg</code> (ou quel que soit le nom que vous lui avez donné) et <code>logo.png</code>.</p> <p class="wp-block-paragraph">À ce stade, vous pourriez techniquement ouvrir le <code>index.html</code> fichier directement dans votre navigateur Web (comme Chrome ou Firefox) pour prévisualiser son apparence statique !</p> <h2 class="wp-block-heading" id="step-3-adding-interactivity-dynamic-content-java-script-script-js">Étape 3 : Ajout d’interactivité et de contenu dynamique (JavaScript – <code>script.js</code>)</h2> <p class="wp-block-paragraph">Donnons maintenant vie à notre page statique en utilisant JavaScript.</p> <p class="wp-block-paragraph">Créez un fichier nommé <code>script.js</code> dans ton <code>mon-écran-de-chargement</code> dossier.</p> <p class="wp-block-paragraph">Nous ajouterons des fonctionnalités pour :</p> <ol class="wp-block-list"> <li>Simulation de la progression du chargement.</li> <li>Affichage de messages dynamiques/changeants.</li> <li>Ajout de musique de fond avec des commandes.</li> <li>Gestion des événements FiveM NUI (la bonne façon d'obtenir la progression du chargement).</li> </ol> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Wait for the DOM (Document Object Model - the HTML structure) to be fully loaded document.addEventListener('DOMContentLoaded', () => { // --- Get References to HTML Elements --- const progressBarInner = document.getElementById('progress-bar-inner'); const progressText = document.getElementById('progress-text'); const dynamicMessage = document.getElementById('dynamic-message'); const loadingMessage = document.getElementById('loading-message'); // To update stages // --- Configuration --- const messages = [ "Loading core systems...", "Establishing network connection...", "Downloading latest server assets...", "Syncing player data...", "Parsing map details...", "Almost there, preparing the world...", "Tip: Visit our Discord at discord.gg/yourinvite", "Tip: Check the rules on our website yourwebsite.com", "Welcome to Our Awesome Server!" ]; let currentMessageIndex = 0; const messageChangeInterval = 5000; // Change message every 5 seconds (5000ms) // Background Music (Optional) const backgroundMusic = new Audio('audio/background_music.ogg'); // IMPORTANT: Use .ogg for FiveM compatibility backgroundMusic.volume = 0.5; // Set initial volume (0.0 to 1.0) backgroundMusic.loop = true; // Loop the music const playPauseButton = document.getElementById('play-pause-button'); const volumeSlider = document.getElementById('volume-slider'); let isPlaying = false; // Track music state // --- Functions --- // Function to update the progress bar and text function updateProgress(percentage) { percentage = Math.min(100, Math.max(0, percentage)); // Clamp between 0 and 100 progressBarInner.style.width = `${percentage}%`; progressText.textContent = `${Math.round(percentage)}%`; } // Function to change the dynamic message function changeDynamicMessage() { dynamicMessage.style.opacity = 0; // Fade out setTimeout(() => { currentMessageIndex = (currentMessageIndex + 1) % messages.length; dynamicMessage.textContent = messages[currentMessageIndex]; dynamicMessage.style.opacity = 1; // Fade in }, 500); // Wait for fade out transition (0.5s) } // Function to attempt playing music (handles browser autoplay restrictions) function playMusic() { backgroundMusic.play().then(() => { isPlaying = true; playPauseButton.textContent = 'Pause Music'; console.log("Music started playing."); }).catch(error => { // Autoplay was prevented, common in browsers until user interaction console.log("Music autoplay failed. Waiting for user interaction.", error); isPlaying = false; playPauseButton.textContent = 'Play Music'; // We might need a click listener on the body or button to initiate playback }); } // --- Initial Setup --- // Set initial loading message loadingMessage.textContent = "Initializing..."; updateProgress(0); // Start progress at 0% // Start changing dynamic messages dynamicMessage.textContent = messages[0]; // Show the first message immediately setInterval(changeDynamicMessage, messageChangeInterval); // Try to play music automatically playMusic(); // Attempt background music playback // --- Event Listeners --- // Music Controls Event Listeners playPauseButton.addEventListener('click', () => { if (isPlaying) { backgroundMusic.pause(); isPlaying = false; playPauseButton.textContent = 'Play Music'; } else { // Important: Re-trigger play function which handles potential initial failures playMusic(); } }); volumeSlider.addEventListener('input', (event) => { backgroundMusic.volume = event.target.value; }); // --- FiveM NUI Event Handling --- // This is the CORE of interacting with the FiveM loading process /* FiveM NUI messages are sent via JavaScript events. We listen for 'message' events on the window object. The event 'data' property contains the information sent from Lua. */ window.addEventListener('message', function(event) { const data = event.data; // Check for the specific NUI message type used by FiveM for loading progress // The 'loadstatus' event provides overall progress text. if (data.type === 'loadstatus') { if(data.status) { loadingMessage.textContent = data.status; } } // The 'progress' event provides detailed component progress (use this for the bar) else if (data.eventName === 'progress') { // data.loadFraction gives a value between 0.0 and 1.0 const progressPercentage = data.loadFraction * 100; updateProgress(progressPercentage); } // A custom event we might send from Lua when loading is almost done else if (data.type === 'loadingComplete') { updateProgress(100); loadingMessage.textContent = "Loading Complete! Joining server..."; // You could add fade-out effects here before the screen disappears } }); // --- Fallback/Simulated Progress (If NUI events aren't received or for testing) --- // Comment this out or remove it if you rely solely on FiveM NUI events /* let simulatedProgress = 0; const interval = setInterval(() => { simulatedProgress += Math.random() * 5; // Increment by a random small amount if (simulatedProgress >= 100) { simulatedProgress = 100; clearInterval(interval); // Stop the simulation when 100% is reached loadingMessage.textContent = "Loading Complete! Joining server..."; // Update final message } updateProgress(simulatedProgress); }, 300); // Update every 300ms */ // Add a small fade-in effect for the whole screen on load document.body.style.opacity = 0; setTimeout(() => { document.body.style.transition = 'opacity 1s ease-in-out'; document.body.style.opacity = 1; }, 100); // Start fade-in slightly after load }); // End DOMContentLoaded</pre> <p class="wp-block-paragraph"><strong>Explication:</strong></p> <ol class="wp-block-list"> <li><strong><code>document.addEventListener('DOMContentLoaded', () => { ... });</code></strong>: Cela garantit que le code JavaScript s'exécute uniquement <em>après</em> la structure entière de la page HTML a été chargée et est prête à être manipulée.</li> <li><strong>Références des éléments :</strong> Nous obtenons des références aux éléments HTML avec lesquels nous devons interagir en utilisant <code>document.getElementById()</code>C'est pourquoi il est important d'avoir des identifiants uniques dans le HTML.</li> <li><strong>Configuration:</strong> <ul class="wp-block-list"> <li><code>messages</code>: Un tableau contenant les différentes chaînes de texte à parcourir dans la zone de message dynamique. Personnalisez-les !</li> <li><code>currentMessageIndex</code>: Garde une trace du message actuellement affiché.</li> <li><code>messageChangeInterval</code>: Définit la fréquence (en millisecondes) à laquelle le message change.</li> </ul> </li> <li><strong>Configuration de la musique de fond :</strong> <ul class="wp-block-list"> <li><code>nouveau Audio('audio/background_music.ogg')</code>: Crée un objet audio HTML. <strong>Fondamentalement :</strong> <ul class="wp-block-list"> <li>Créer un <code>audio</code> dossier à l'intérieur <code>mon-écran-de-chargement</code>.</li> <li>Placez votre fichier de musique de fond ici.</li> <li><strong>Utilisez le <code>.ogg</code> format!</strong> Les formats MP3 et autres peuvent être peu fiables, voire inopérants, dans FiveM NUI. Vous trouverez facilement des convertisseurs en ligne pour convertir des fichiers MP3 en OGG.</li> </ul> </li> <li><code>backgroundMusic.volume</code>: Définit le volume initial (0,0 = silencieux, 1,0 = plein).</li> <li><code>backgroundMusic.loop = vrai;</code>:Fait répéter la musique.</li> <li>Nous obtenons également des références au bouton lecture/pause et au curseur de volume.</li> </ul> </li> <li><strong><code>updateProgress(pourcentage)</code> fonction:</strong> Prend un nombre (0-100), le fixe pour s'assurer qu'il est dans les limites, met à jour le <code>largeur</code> style de l'élément de la barre de progression interne et modifie le contenu du texte de l'affichage du pourcentage.</li> <li><strong><code>changeDynamicMessage()</code> fonction:</strong> <ul class="wp-block-list"> <li>Utilisations <code>setInterval</code> dans la phase de configuration pour appeler cette fonction à plusieurs reprises.</li> <li>Il calcule l'index du message suivant, en l'enroulant autour à l'aide de l'opérateur modulo (<code>%</code>).</li> <li>Met à jour le <code>Contenu du texte</code> de la <code>Message dynamique</code> élément.</li> <li><em>Prime:</em> Inclut un effet simple de fondu enchaîné/fondu enchaîné utilisant l'opacité CSS et <code>définirTimeout</code> pour une transition plus douce. Ajouter <code>transition : opacité 0,5 s entrée-sortie progressive ;</code> au <code>.zone de message p</code> sélecteur dans votre CSS pour que cela fonctionne visuellement.</li> </ul> </li> <li><strong><code>jouerMusique()</code> fonction:</strong> Tente de jouer la musique en utilisant <code>backgroundMusic.play()</code>. Le <code>.alors()</code> gère la lecture réussie, tandis que <code>.attraper()</code> Gère les erreurs, souvent liées aux restrictions de lecture automatique du navigateur (nécessitant une intervention préalable de l'utilisateur). Le texte du bouton est mis à jour en conséquence.</li> <li><strong>Configuration initiale :</strong> Définit le texte initial, réinitialise la progression à 0, affiche le premier message dynamique et démarre le minuteur d'intervalle pour les modifications de message. Il appelle également <code>jouerMusique()</code> pour essayer de démarrer l'audio.</li> <li><strong>Écouteurs d'événements (commandes musicales) :</strong> <ul class="wp-block-list"> <li>Écoute les clics sur le <code>Bouton playPause</code>Si la musique est en cours de lecture, il la met en pause ; sinon, il appelle <code>jouerMusique()</code> encore une fois (important pour gérer les cas où la lecture automatique initiale a échoué).</li> <li>Écoute pour <code>saisir</code> événements sur le <code>volumeSlider</code> (se déclenche en continu lorsque le curseur se déplace) et met à jour le <code>backgroundMusic.volume</code>.</li> </ul> </li> <li><strong>Gestion des événements FiveM NUI (<code>window.addEventListener('message', ...)</code>):</strong> <ul class="wp-block-list"> <li><strong>C'est la partie la plus importante pour <em>réel</em> intégration.</strong> FiveM envoie des messages à la fenêtre NUI (votre page HTML) en utilisant le <code>postMessage</code> API.</li> <li>Nous écoutons ces messages sur le <code>fenêtre</code> objet.</li> <li><code>données d'événement</code> contient la charge utile envoyée depuis <a href="https://fivemx.com/fr/conversion-de-scripts-fivem/" title="Conversion de scripts FiveM – ESX, QBCore, QBOX (Guide du framework)" data-wpil-monitor-id="1644">Scripts Lua de FiveM</a>.</li> <li>Nous vérifions <code>événement.data.type</code> ou <code>événement.données.nom_événement</code> (différentes versions/contextes FiveM peuvent utiliser des structures légèrement différentes) pour voir de quel type de message il s'agit.</li> <li><code>'état de chargement'</code>: Contient souvent un texte d'état général (par exemple, « Chargement de la carte », « Initialisation des scripts »). Nous mettons à jour <code>chargement du message</code> paragraphe.</li> <li><code>'progrès'</code>: Ceci est généralement utilisé pour la progression réelle de la barre de chargement. <code>données.loadFraction</code> fournit généralement une valeur comprise entre 0,0 et 1,0, que nous convertissons en pourcentage et introduisons dans notre <code>mise à jourProgress</code> fonction.</li> <li><code>'chargement terminé'</code>:Ce n'est pas un événement FiveM standard, mais un exemple de <em>coutume</em> vous envoyer un message <em>pourrait</em> envoyer à partir d'un script Lua (dont nous parlerons plus tard) pour signaler la fin du chargement, vous permettant de définir la progression sur 100% et d'afficher un message final.</li> </ul> </li> <li><strong>Repli/Progression simulée :</strong> <ul class="wp-block-list"> <li>La section commentée fournit un <em>simulation de base</em> du progrès. Il utilise <code>setInterval</code> pour incrémenter périodiquement la barre de progression d'une petite quantité aléatoire.</li> <li><strong>Ceci est utile pour tester visuellement votre écran de chargement dans un navigateur <em>sans</em> exécuter FiveM.</strong></li> <li><strong>Vous devez SUPPRIMER ou COMMENTER ce code de simulation lorsque vous utilisez les événements FiveM NUI réels</strong>, sinon, vous risquez de voir des mises à jour de progression contradictoires.</li> </ul> </li> <li><strong>Effet de fondu entrant :</strong> Ajoute un fondu subtil pour l'ensemble du corps lorsque la page se charge pour une apparence plus fluide.</li> </ol> <p class="wp-block-paragraph">Enregistrer ce fichier sous <code>script.js</code>. N'oubliez pas de créer le <code>audio</code> dossier et ajoutez votre <code>.ogg</code> fichier musical.</p> <h2 class="wp-block-heading" id="step-4-integrating-with-five-m-lua-fxmanifest-lua">Étape 4 : Intégration avec FiveM (Lua – <code>fxmanifest.lua</code>)</h2> <p class="wp-block-paragraph">Nous devons maintenant informer le serveur FiveM de notre nouvelle ressource et l'identifier comme un écran de chargement.</p> <p class="wp-block-paragraph">Créez un fichier nommé <code>fxmanifest.lua</code> à la racine de votre <code>mon-écran-de-chargement</code> dossier.</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">-- Resource Manifest fx_version 'cerulean' -- Use 'cerulean' or a newer version like 'adamant' or 'bodacious' game 'gta5' author 'Your Name or Server Name' description 'Custom Loading Screen for My Awesome Server' version '1.0.0' -- Specify this resource as the loading screen loadscreen 'index.html' -- List all files needed by the UI (HTML, CSS, JS, images, audio, fonts, etc.) files { 'index.html', 'style.css', 'script.js', 'images/logo.png', 'images/background.jpg', -- Add all your images here 'audio/background_music.ogg' -- Add all your audio files here -- 'fonts/mycustomfont.woff2' -- Add custom fonts if you use any } -- Optional: Client script for advanced control (like hiding default elements) client_script 'client.lua' -- Optional: If your loading screen needs to fetch data FROM the server (more advanced) -- server_script 'server.lua' -- Optional: Define NUI settings if needed (rarely required for basic loading screens) -- nui_settings { -- ['scriptFramePolicy'] = "frame-ancestors 'self' https:\/\/cfx.re" -- Example security policy -- }</pre> <p class="wp-block-paragraph"><strong>Explication:</strong></p> <ul class="wp-block-list"> <li><strong><code>fx_version 'céruléen'</code></strong>: Définit la version du manifeste. « cerulean » est une référence courante, mais des versions plus récentes comme « adamant » ou « bodacious » existent. Conservez « cerulean », sauf si vous avez besoin de fonctionnalités de versions plus récentes.</li> <li><strong><code>jeu 'gta5'</code></strong>: Spécifie le jeu pour lequel cette ressource est destinée.</li> <li><strong><code>auteur</code>, <code>description</code>, <code>version</code></strong>Métadonnées concernant votre ressource. Renseignez-les correctement.</li> <li><strong><code>écran de chargement 'index.html'</code></strong>: <strong>C'est la ligne cruciale.</strong> Il indique à FiveM d'utiliser le fichier HTML spécifié (<code>index.html</code> (dans notre cas) comme écran de chargement du jeu.</li> <li><strong><code>fichiers { ... }</code></strong>: <strong>Très important !</strong> Vous devez lister <em>chaque fichier</em> que votre page HTML doit charger, par rapport au dossier racine de la ressource. Cela inclut : <ul class="wp-block-list"> <li>Le fichier HTML lui-même (<code>index.html</code>)</li> <li>Le fichier CSS (<code>style.css</code>)</li> <li>Le fichier JavaScript (<code>script.js</code>)</li> <li>Toutes les images (par exemple, <code>images/logo.png</code>, <code>images/background.jpg</code>)</li> <li>Tous les fichiers audio (par exemple, <code>audio/musique_de_fond.ogg</code>)</li> <li>Toutes les polices personnalisées que vous pourriez avoir liées dans votre CSS.</li> <li><em>Si vous oubliez un fichier ici, il ne se chargera pas dans le jeu !</em></li> </ul> </li> <li><strong><code>script_client 'client.lua'</code></strong>:Nous incluons ceci car nous allons créer un petit script client à l'étape suivante pour gérer le masquage des éléments de chargement FiveM par défaut.</li> <li><strong><code>script_serveur 'server.lua'</code></strong>: Uniquement nécessaire pour les scénarios avancés où votre écran de chargement doit communiquer avec le serveur (par exemple, récupérer le nombre de joueurs dynamiques) <em>avant</em> L'environnement de jeu principal se charge, ce qui est complexe. Nous ne l'utiliserons pas pour une configuration de base.</li> <li><strong><code>nui_settings</code></strong>Permet de définir des politiques de sécurité spécifiques pour le cadre NUI. Généralement inutile pour les écrans de chargement standard, sauf si vous intégrez du contenu externe ou gérez des interactions complexes.</li> </ul> <p class="wp-block-paragraph">Enregistrer ce fichier sous <code>fxmanifest.lua</code>.</p> <p class="wp-block-paragraph"><em>(Remarque : les serveurs plus anciens peuvent utiliser <code>__ressource.lua</code> au lieu de <code>fxmanifest.lua</code>. La syntaxe est très similaire, mais <code>version_fx</code> est généralement omis ou différent, et les directives peuvent varier légèrement. <code>fxmanifest.lua</code> est la norme moderne).</em></p> <h2 class="wp-block-heading" id="step-5-disabling-the-default-five-m-bridge-animation-lua-client-lua">Étape 5 : Désactivation de l’animation par défaut du pont FiveM (Lua – <code>client.lua</code>)</h2> <p class="wp-block-paragraph">Par défaut, FiveM affiche son propre texte de chargement et parfois une animation de chargement de « pont » <em>avant</em> Votre écran personnalisé prend entièrement le dessus. Nous pouvons masquer ces éléments pour un rendu plus épuré grâce à un script Lua côté client.</p> <div class="wp-block-buttons is-layout-flex wp-block-buttons-is-layout-flex"> <div class="wp-block-button is-style-fill"><a class="wp-block-button__link has-white-color has-black-background-color has-text-color has-background has-link-color wp-element-button" href="https://fivemx.com/fr/desactiver-lelement-de-pont-dans-lecran-de-chargement-fivem/">Désactiver l'animation du pont</a></div> </div> <p class="wp-block-paragraph">Créez un fichier nommé <code>client.lua</code> dans ton <code>mon-écran-de-chargement</code> dossier.</p> <pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">-- client.lua for the loading screen resource -- This code runs as soon as the resource starts on the client -- We wait a brief moment to ensure NUI is likely ready Citizen.Wait(100) -- Method 1: Using ShutdownLoadingScreenNui (Recommended for simple hiding) -- This attempts to immediately hide the default GTA loading UI elements. -- It's often effective, but timing can sometimes be tricky depending on client load speed. ShutdownLoadingScreenNui() -- You can also send a message to your NUI page if needed, for example, -- to signal that Lua is ready or pass initial data. -- SendNUIMessage({ -- type = "luaReady", -- message = "Client script has loaded!" -- }) -- Method 2: More controlled hiding using CreateThread and AddTextEntry -- This method continuously overrides the default loading text entries. -- It can be more reliable in ensuring default text doesn't flicker briefly. -- Uncomment this section and comment out ShutdownLoadingScreenNui() if you prefer this. --[[ Citizen.CreateThread(function() -- Hide the default "Initializing..." text components AddTextEntry('FE_THDR_GTAO', ' ') -- Loading Online AddTextEntry('PM_NAME_APP', ' ') -- GTA Application Name (might vary) AddTextEntry('PM_INFO_DET', ' ') -- Build Info \/ Connecting status AddTextEntry('LOADING_SPLAYER_L', ' ') -- Loading Story Mode (sometimes appears) AddTextEntry('DLC_ITEM_UNLOCK', ' ') -- open messages if any -- Keep overriding them periodically while the custom screen is expected to be active -- This loop might be excessive; often just setting them once is enough. -- Adjust the Wait time or remove the loop if performance is impacted. while true do Citizen.Wait(500) -- Check\/override every 500ms -- Check if the loading screen is still active (pseudo-code, needs actual logic) -- local isLoading = GetIsLoadingScreenActive() -- This native might not work early enough -- if not isLoading then break end -- Exit loop when main game loads (needs better condition) -- Re-apply overrides just in case AddTextEntry('FE_THDR_GTAO', ' ') AddTextEntry('PM_NAME_APP', ' ') AddTextEntry('PM_INFO_DET', ' ') AddTextEntry('LOADING_SPLAYER_L', ' ') AddTextEntry('DLC_ITEM_UNLOCK', ' ') -- Optionally, hide the rotating loading circle in the bottom right HideHudComponentThisFrame(14) -- HUD_LOADING_SPINNER end end) --]] -- You can add more logic here if needed, for example, listening for game events -- to send specific messages to your NUI loading screen. -- Example: Send a message when the player spawns (though loading screen is usually gone by then) -- AddEventHandler('playerSpawned', function() -- SendNUIMessage({ type = 'playerReady' }) -- end) print('[MyLoadingScreen] Client script loaded.')</pre> <p class="wp-block-paragraph"><strong>Explication:</strong></p> <ul class="wp-block-list"> <li><strong><code>Citoyen.Attendez(100)</code></strong>:Un léger retard. J'essaie parfois d'interagir avec l'interface utilisateur ou des éléments du jeu. <em>immédiatement</em> Le chargement du script peut échouer. Cela laisse le temps à l'initialisation.</li> <li><strong><code>ShutdownLoadingScreenNui()</code></strong>: Il s'agit d'une fonction native de FiveM spécialement conçue pour masquer les éléments d'interface utilisateur par défaut de l'écran de chargement fournis par le jeu ou FiveM lui-même. C'est généralement la méthode la plus simple et la plus directe.</li> <li><strong><code>EnvoyerNUIMessage({ ... })</code></strong>:Un exemple montrant comment vous pouvez envoyer des données <em>depuis</em> Lua <em>à</em> votre JavaScript. Le tableau que vous transmettez devient le <code>données d'événement</code> objet dans votre <code>window.addEventListener('message', ...)</code> auditeur dans <code>script.js</code>Vous pouvez l'utiliser pour déclencher des actions spécifiques ou transmettre des informations sur le serveur.</li> <li><strong>Méthode 2 (commentée) :</strong> <ul class="wp-block-list"> <li>Fournit une approche alternative en utilisant <code>Ajouter une entrée de texte</code>. Cette fonction vous permet de remplacer les chaînes de texte de jeu par défaut identifiées par leurs clés (comme <code>FE_THDR_GTAO</code>). En les définissant avec un espace (' '), vous les masquez efficacement.</li> <li>Le <code>Citoyen.Créer un fil de discussion</code> crée un thread séparé pour cette tâche.</li> <li>Le <code>bien que vrai</code> boucle (avec <code>Citoyen.Attendez</code>) applique continuellement ces remplacements. Cela peut être plus fiable contre la tentative du jeu de réinitialiser le texte, mais peut être excessif. Il inclut également <code>MasquerHudComponentThisFrame(14)</code> pour cacher la toupie.</li> <li><strong>Choisir <em>un</em> méthode.</strong> En utilisant <code>ShutdownLoadingScreenNui()</code> est généralement préféré pour la simplicité, sauf si vous rencontrez des problèmes où les éléments par défaut clignotent encore brièvement.</li> </ul> </li> <li><strong><code>imprimer(...)</code></strong>: Enregistre un message sur la console F8 du client, utile pour confirmer le script chargé.</li> </ul> <p class="wp-block-paragraph">Enregistrer ce fichier sous <code>client.lua</code>.</p> <h2 class="wp-block-heading" id="step-6-installing-and-running-the-loading-screen">Étape 6 : Installation et exécution de l'écran de chargement</h2> <p class="wp-block-paragraph">Maintenant que toutes les pièces sont créées, mettons-les sur le serveur.</p> <ol class="wp-block-list"> <li><strong>Télécharger la ressource :</strong> <ul class="wp-block-list"> <li>Prenez l'intégralité <code>mon-écran-de-chargement</code> dossier (qui contient désormais <code>index.html</code>, <code>style.css</code>, <code>script.js</code>, <code>fxmanifest.lua</code>, <code>client.lua</code>, et le <code>images</code> et <code>audio</code> sous-dossiers avec leur contenu).</li> <li>Téléchargez ce dossier complet sur votre serveur FiveM <code>ressources</code> Répertoire. Vous pouvez utiliser un logiciel FTP (comme FileZilla) ou le panneau web de votre hébergeur. La structure devrait ressembler à ceci : <code>[server-data]/resources/mon-écran-de-chargement/</code>.</li> </ul> </li> <li><strong>Assurer la ressource en <code>serveur.cfg</code>:</strong> <ul class="wp-block-list"> <li>Ouvrez le fichier de configuration principal de votre serveur, généralement nommé <code>serveur.cfg</code>.</li> <li>Recherchez la section où les ressources sont démarrées (lignes commençant généralement par <code>assurer</code> ou <code>commencer</code>).</li> <li>Ajoutez une ligne pour démarrer votre ressource d'écran de chargement :<br><code>Écran de chargement personnalisé cfg #</code></li> <li><strong>Le placement importe légèrement :</strong> Assurez-vous qu'il est répertorié <em>avant</em> Des ressources qui peuvent prendre du temps à charger si vous souhaitez que l'écran apparaisse le plus tôt possible. Cependant, des ressources de base <code>assurer</code> est généralement suffisant. Faire <em>pas</em> placez-le à l'intérieur de n'importe quel <code>[catégorie]</code> entre parenthèses si vous souhaitez qu'il s'agisse d'une ressource par défaut.</li> </ul> </li> <li><strong>Redémarrez votre serveur :</strong> Pour les changements dans <code>serveur.cfg</code> et pour que la nouvelle ressource soit reconnue, vous devez redémarrer complètement votre serveur FiveM.</li> <li><strong>Connectez et testez :</strong> Lancez FiveM et connectez-vous à votre serveur. Vous devriez maintenant voir votre écran de chargement personnalisé au lieu de celui par défaut ! Testez la barre de progression (elle devrait réagir au chargement de FiveM), les messages changeants et les commandes musicales. Vérifiez la console F8 en jeu pour détecter d'éventuelles erreurs. <code>client.lua</code> ou des problèmes potentiels liés à l'interface utilisateur NUI. Vérifiez la console du navigateur (souvent accessible via F8 -> Outils NUI, ou en ouvrant directement le code HTML) pour détecter les erreurs JavaScript.</li> </ol> <h2 class="wp-block-heading" id="advanced-customization-ideas">Idées de personnalisation avancées</h2> <p class="wp-block-paragraph">Une fois que vous maîtrisez les bases, vous pouvez explorer des fonctionnalités plus avancées :</p> <ul class="wp-block-list"> <li><strong>Vidéos d'arrière-plan :</strong> Au lieu d'une image statique, utilisez un code HTML <code><video></code> étiqueter. <ul class="wp-block-list"> <li>Ajouter <code><video autoplay muted loop id="bg-video"></video></code> à votre <code>index.html</code>.</li> <li>Style <code>#bg-vidéo</code> en CSS similaire au <code>.arrière-plan</code> div (position absolue, 100% largeur/hauteur, <code>objet-ajustement : couverture</code>, <code>z-index: -1</code>).</li> <li><strong>Important:</strong> Les vidéos augmentent considérablement la taille de l'écran de chargement. Optimisez-les fortement (résolution, débit binaire). Utilisez des formats tels que <code>.mp4</code> (Codec H.264). N'oubliez pas d'ajouter le fichier vidéo à <code>fxmanifest.lua</code>La lecture automatique peut nécessiter <code>en sourdine</code> attribut initialement dû aux politiques du navigateur ; vous pourriez avoir besoin de JS pour réactiver le son en fonction de l'interaction de l'utilisateur (comme cliquer sur le contrôle du volume).</li> </ul> </li> <li><strong>Récupération dynamique des règles/messages du serveur :</strong> Au lieu de coder en dur les messages en JS, utilisez <code>aller chercher</code> dans ton <code>script.js</code> pour charger des règles ou des annonces à partir d'un <code>.json</code> fichier dans votre ressource ou même depuis un serveur web/API externe. Cela facilite les mises à jour.</li> <li><strong>Utilisation des frameworks Web :</strong> Utilisez des frameworks CSS comme Tailwind CSS ou Bootstrap pour un style plus rapide, ou des frameworks JavaScript comme Vue.js ou React pour une logique d'interface utilisateur plus complexe (bien que cela ajoute une complexité et des étapes de construction importantes).</li> <li><strong>Intégrations API :</strong> Récupérez des données depuis des API externes (par exemple, affichez le nombre de joueurs en ligne depuis votre serveur Discord à l'aide d'un bot Discord et d'un point de terminaison API simple). Cela nécessite un script côté serveur.<code>serveur.lua</code> dans votre ressource ou un service Web distinct) pour gérer en toute sécurité.</li> <li><strong>Animations plus sophistiquées :</strong> Utiliser des animations CSS (<code>@keyframes</code>) ou des bibliothèques d'animation JavaScript (comme GSAP) pour des transitions plus fluides, des effets de fondu ou des logos animés.</li> </ul> <h2 class="wp-block-heading" id="troubleshooting-common-issues">Dépannage des problèmes courants</h2> <ul class="wp-block-list"> <li><strong>L'écran de chargement n'apparaît pas :</strong> <ul class="wp-block-list"> <li>Vérifier <code>serveur.cfg</code>: Est <code>assurer mon-écran-de-chargement</code> Présent et orthographié correctement ? Y a-t-il des erreurs dans la console du serveur au démarrage liées à la ressource ?</li> <li>Vérifier <code>fxmanifest.lua</code>: Est-ce que le <code>écran de chargement 'index.html'</code> ligne correcte ? Sont <em>tous</em> fichiers nécessaires (HTML, CSS, JS, images, audio) répertoriés dans le <code>fichiers</code> bloc ? Vérifiez soigneusement les noms de fichiers et les chemins (sensible à la casse sous Linux !).</li> <li>Vérifier la structure du dossier : est-ce que le <code>mon-écran-de-chargement</code> dossier directement à l'intérieur du <code>ressources</code> dossier?</li> </ul> </li> <li><strong>Styles CSS non appliqués :</strong> <ul class="wp-block-list"> <li>Vérifier le HTML <code></code> tag : Est-ce que le <code>href="style.css"</code> correct?</li> <li>Vérifier <code>fxmanifest.lua</code>: Est <code>style.css</code> répertorié dans le <code>fichiers</code> bloc?</li> <li>Vérifiez la syntaxe CSS : y a-t-il des fautes de frappe ou des erreurs dans votre <code>style.css</code> fichier ? Utilisez un validateur CSS.</li> <li>Cache du navigateur : Parfois, le cache NUI de FiveM conserve d'anciennes versions. Videz votre cache FiveM (généralement dans <code>%localappdata%FiveMFiveM.appcache</code> sous Windows, supprimez des dossiers comme <code>navigateur</code>, <code>db</code>, <code>stockage nui</code>) et redémarrez FiveM.</li> </ul> </li> <li><strong>JavaScript ne fonctionne pas (pas de progression, pas de changement de message, pas de musique) :</strong> <ul class="wp-block-list"> <li>Vérifier le HTML <code></code> tag : Est-ce que le <code>src="script.js"</code> correcte et placée à la <em>fin</em> de la <code><body></code>?</li> <li>Vérifier <code>fxmanifest.lua</code>: Est <code>script.js</code> répertorié dans le <code>fichiers</code> bloc?</li> <li>Vérifiez la console du navigateur : ouvrez la console F8 dans FiveM, accédez à NUI Devtools (si disponible) ou ouvrez le <code>index.html</code> directement dans un navigateur et vérifiez la console développeur (généralement F12) pour détecter les erreurs JavaScript. Ces erreurs identifient souvent la ligne problématique.</li> <li>Problèmes audio : le fichier musical est-il dans <code>.ogg</code> format ? Le chemin est-il dans <code>nouveau Audio(...)</code> Est-ce correct ? <code>audio/votre_musique.ogg</code> Répertorié dans le manifeste ? N'oubliez pas les restrictions de lecture automatique du navigateur : la musique peut ne démarrer qu'après avoir cliqué sur le bouton de lecture.</li> </ul> </li> <li><strong>La barre de progression ne se met pas à jour :</strong> <ul class="wp-block-list"> <li>Comptez-vous sur les événements FiveM NUI (<code>window.addEventListener('message', ...)</code>? Assurez-vous que ce code est actif (non commenté).</li> <li>Les noms des événements sont-ils (<code>état de charge</code>, <code>progrès</code>, <code>Fraction de charge</code>) correct ? Ces informations peuvent parfois varier légèrement selon les mises à jour de FiveM ou les versions de jeu spécifiques. Ajouter <code>console.log(JSON.stringify(event.data))</code> à l'intérieur de l'écouteur de messages pour voir exactement quelles données FiveM envoie.</li> <li>L'ID de l'élément est-il (<code>barre de progression intérieure</code>) correct en HTML et en JS ?</li> </ul> </li> <li><strong>Éléments de chargement FiveM par défaut toujours visibles :</strong> <ul class="wp-block-list"> <li>Vérifier <code>client.lua</code>: Le script est-il en cours d'exécution (vérifiez le <code>imprimer</code> message dans F8) ? Est-ce <code>ShutdownLoadingScreenNui()</code> appelé ? Si vous utilisez <code>Ajouter une entrée de texte</code>Les touches sont-elles adaptées à votre configuration de jeu ? Essayez d'augmenter la valeur initiale. <code>Citoyen.Attendre()</code>.</li> </ul> </li> </ul> <h2 class="wp-block-heading" id="need-a-premium-solution-check-out-five-mx">Besoin d'une solution premium ? Découvrez FiveMX !</h2> <p class="wp-block-paragraph">Créer un écran de chargement à partir de zéro est gratifiant, mais cela peut également prendre du temps, surtout si vous souhaitez des fonctionnalités avancées et une conception très soignée.</p> <p class="wp-block-paragraph">Si vous préférez une solution professionnelle prête à l'emploi, nous avons ce qu'il vous faut ici chez FiveMX.</p> <p class="wp-block-paragraph">Nous proposons une sélection organisée d'écrans de chargement premium et riches en fonctionnalités, conçus par des développeurs expérimentés.</p> <p class="wp-block-paragraph"><strong>Avantages des écrans de chargement payants FiveMX :</strong></p> <ul class="wp-block-list"> <li><strong>Conceptions professionnelles :</strong> Esthétique visuellement époustouflante et moderne.</li> <li><strong>Fonctionnalités avancées :</strong> Incluez souvent des vidéos d'arrière-plan, des lecteurs de musique, plusieurs sections configurables, des aperçus d'intégration Discord, des indicateurs d'état du serveur, etc.</li> <li><strong>Configuration facile :</strong> Ils sont généralement livrés avec des fichiers de configuration simples pour personnaliser le texte, les logos, les liens et les fonctionnalités sans nécessiter de modifications de code profondes.</li> <li><strong>Fiabilité et support :</strong> Testé pour la compatibilité et souvent accompagné d'un support développeur si vous rencontrez des problèmes.</li> <li><strong>Gagnez du temps et des efforts :</strong> Obtenez un résultat détaillé instantanément, vous permettant de vous concentrer sur d'autres aspects de votre serveur.</li> </ul> <p class="wp-block-paragraph">Explorez notre gamme d'interfaces et d'écrans de chargement pour trouver la solution idéale pour l'identité de votre serveur :</p> <ul class="wp-block-list"> <li>Catégorie Écrans de chargement FiveMX</li> <li>Collection de scripts FiveMX (la section Interfaces inclut souvent des écrans de chargement)</li> </ul> <p class="wp-block-paragraph">Considérez ces options populaires disponibles sur FiveMX :</p> <ol class="wp-block-list"> <li><strong>Écran de chargement moderne V1</strong>:Une option élégante et propre pour vous aider à démarrer.</li> <li><strong>Écran de chargement avancé V6</strong>:Rempli de fonctionnalités pour une personnalisation ultime.</li> <li><strong>Écran de chargement unique V13</strong>: différencier la configuration avec un design distinctif.</li> <li><strong>Écran de chargement V16</strong>:Un autre excellent choix avec des fonctionnalités modernes.</li> </ol> <p class="wp-block-paragraph">Investir dans un écran de chargement premium peut considérablement améliorer la qualité perçue de votre serveur et l'expérience du joueur dès le premier clic.</p> <h2 class="wp-block-heading" id="conclusion">Conclusion</h2> <p class="wp-block-paragraph">Créer un <strong>Écran de chargement FiveM personnalisé</strong> est un moyen puissant d'améliorer l'identité du serveur et de fournir une meilleure expérience utilisateur.</p> <p class="wp-block-paragraph">Nous avons parcouru la configuration de la structure HTML, son style avec CSS, l'ajout d'un comportement dynamique avec JavaScript et son intégration dans FiveM à l'aide du <code>fxmanifest.lua</code> et un simple <code>client.lua</code> script pour masquer les éléments par défaut.</p> <p class="wp-block-paragraph">N'oubliez pas que la clé réside dans une gestion minutieuse des fichiers (en listant tout dans le manifeste), en comprenant comment fonctionnent les événements NUI pour les mises à jour de progression réelles et en utilisant les normes Web (HTML, CSS, JS).</p> <p class="wp-block-paragraph">N’ayez pas peur d’expérimenter différents styles, messages et médias.</p> <p class="wp-block-paragraph">Testez minutieusement dans votre navigateur et dans le jeu, en utilisant les consoles de développement pour déboguer les problèmes.</p> <p class="wp-block-paragraph">Que vous construisiez votre propre chef-d'œuvre en suivant ce guide ou que vous choisissiez une option premium raffinée de FiveMX.com, investir dans votre écran de chargement revient à investir dans la première impression de votre serveur.</p> <p class="wp-block-paragraph">Bon codage, et nous espérons que cela vous aidera à créer un point d’entrée incroyable pour vos joueurs !</p> <h2 class="wp-block-heading" id="frequently-asked-questions-faq">Foire aux questions (FAQ)</h2> <p class="wp-block-paragraph"><strong>Q1 : Puis-je utiliser des vidéos d’arrière-plan au lieu d’images ?</strong></p> <p class="wp-block-paragraph">R : Oui ! Utilisez le code HTML. <code><video></code> étiqueter (<code><video autoplay muted loop id="bg-video"></video></code>). Stylisez-le avec CSS pour couvrir l'écran (<code>position : absolue</code>, <code>largeur : 100%</code>, <code>hauteur : 100%</code>, <code>objet-ajustement : couverture</code>, <code>z-index: -1</code>). N'oubliez pas de <code>muet</code> pour que la lecture automatique fonctionne de manière fiable, optimisez considérablement la taille du fichier vidéo, utilisez des formats compatibles comme MP4 (H.264) et répertoriez le fichier vidéo dans votre <code>fxmanifest.lua</code>.</p> <p class="wp-block-paragraph"><strong>Q2 : Comment puis-je faire en sorte que la barre de progression affiche le <em>réel</em> Progression du chargement de FiveM ?</strong></p> <p class="wp-block-paragraph">R : Le moyen le plus fiable est d’utiliser JavaScript <code>window.addEventListener('message', ...)</code> pour écouter les messages NUI envoyés par FiveM. Plus précisément, recherchez un événement comme <code>progrès</code> qui contient souvent un <code>Fraction de charge</code> propriété (une valeur comprise entre 0,0 et 1,0). Multipliez-la par 100 et transmettez-la à votre <code>mise à jourProgress</code> Fonction JavaScript. Évitez de vous fier uniquement à la progression simulée (comme <code>setInterval</code> (exemple) pour la version finale.</p> <p class="wp-block-paragraph"><strong>Q3 : Où dois-je exactement placer les fichiers d’écran de chargement sur mon serveur ?</strong></p> <p class="wp-block-paragraph">A : Créez un dossier dédié à votre ressource (par exemple, <code>mon-écran-de-chargement</code>) à l'intérieur du serveur principal de votre serveur <code>ressources</code> répertoire. Tous les fichiers (<code>index.html</code>, <code>style.css</code>, <code>script.js</code>, <code>fxmanifest.lua</code>, <code>client.lua</code>, et des sous-dossiers comme <code>images</code>, <code>audio</code>) doit être placé dans ce dossier de ressources.</p> <p class="wp-block-paragraph"><strong>Q4 : Puis-je avoir une musique de fond ? Comment ajouter des commandes ?</strong></p> <p class="wp-block-paragraph">R : Oui. Utilisez le code HTML. <code><audio></code> étiqueter ou créer un <code>Audio</code> objet en JavaScript (<code>nouveau Audio('audio/music.ogg')</code>). <strong>Il est crucial d’utiliser le <code>.ogg</code> format audio</strong> pour une meilleure compatibilité avec FiveM NUI. Ajoutez des boutons HTML standard (<code><button></code>) et potentiellement une entrée de plage (<code></code>) pour le volume dans votre <code>index.html</code>. Utiliser les écouteurs d'événements JavaScript (<code>ajouterEventListener</code>) sur ces éléments pour contrôler l'objet audio <code>.jouer()</code>, <code>.pause()</code>, et <code>.volume</code> propriétés. N'oubliez pas de lister le fichier audio dans votre manifeste.</p> <p class="wp-block-paragraph"><strong>Q5 : Pourquoi mon écran de chargement n'apparaît-il pas du tout ?</strong></p> <p class="wp-block-paragraph">A : Vérifiez deux fois ces coupables courants :<br>1. La ressource est-elle correctement assurée dans <code>serveur.cfg</code> (<code>assurer resource_folder_name</code>)?<br>2. Est-ce que le <code>fxmanifest.lua</code> présent dans le dossier de ressources ?<br>3. Le manifeste a-t-il le <code>écran de chargement 'votre_fichier_html.html'</code> doubler?<br>4. Sont <em>tous</em> fichiers requis (HTML, CSS, JS, images, audio, polices) répertoriés avec précision sous <code>fichiers { ... }</code> dans le manifeste ? Vérifiez les chemins et les noms de fichiers (sensible à la casse !).<br>5. Y a-t-il des erreurs dans la console du serveur ou la console F8 du client liées à l'échec du chargement de la ressource ?<br>6. Avez-vous redémarré le serveur après avoir ajouté la ressource et l'avoir vérifié ?</p> <p class="wp-block-paragraph"><strong>Q6 : Comment puis-je faire en sorte que l'écran de chargement disparaisse en douceur lorsque le jeu démarre ?</strong></p> <p class="wp-block-paragraph">R : Cela nécessite une communication entre votre script Lua et la page NUI. FiveM ne dispose pas d'un événement « Chargement terminé, sur le point d'apparaître » parfaitement fiable et facile à détecter. <em>avant</em> L'interface utilisateur numérique est détruite. Cependant, vous pouvez :<br>1. Envoyez un message NUI personnalisé (<code>EnvoyerNUIMessage({ type = 'loadingAlmostDone' })</code>) à partir d'un script client Lua basé sur certains événements de jeu ou minuteries juste avant l'apparition.<br>2. Dans votre JavaScript, écoutez ce message (<code>si (event.data.type === 'loadingAlmostDone')</code>).<br>3. Une fois reçu, déclenchez une animation de fondu CSS sur votre conteneur principal (<code>.loading-container.fade-out { opacité : 0 ; transition : opacité 1 s ; }</code> et ajoutez le <code>fondu enchaîné</code> classe utilisant JS). Cela crée une transition visuelle, même si l'interface utilisateur graphique (NUI) peut être supprimée brutalement par FiveM par la suite.</p> <h2 class="wp-block-heading" id="p">Écrans de chargement payants</h2> <div data-wp-context="{"notices":[],"hideNextPreviousButtons":false,"isDisabledPrevious":true,"isDisabledNext":false,"ariaLabelPrevious":"Produits pr\u00e9c\u00e9dents","ariaLabelNext":"Produits suivants"}" data-wp-init="callbacks.onRender" data-wp-interactive="woocommerce/product-collection" data-wp-router-region="wc-product-collection-0" data-__private-preview-state="{"isPreview":false,"previewMessage":"Actual products will vary depending on the page being viewed."}" data-block-name="woocommerce/product-collection" data-dimensions="{"widthType":"fill"}" data-display-layout="{"type":"flex","columns":3,"shrinkColumns":true}" data-query-context-includes="["collection"]" data-query-id="0" data-query="{"perPage":9,"pages":0,"offset":0,"postType":"product","order":"asc","orderBy":"title","search":"","exclude":[],"inherit":false,"taxQuery":{"product_cat":[537]},"isProductCollectionBlock":true,"featured":false,"woocommerceOnSale":false,"woocommerceStockStatus":["instock","onbackorder"],"woocommerceAttributes":[],"woocommerceHandPickedProducts":[],"filterable":true,"relatedBy":{"categories":true,"tags":true}}" data-tag-name="div" class="wp-block-woocommerce-product-collection is-layout-flow wp-block-woocommerce-product-collection-is-layout-flow"> <div data-wp-interactive="woocommerce/store-notices" class="wc-block-components-notices alignwide"> <template data-wp-each--notice="state.notices" data-wp-each-key="context.notice.id"> <div class="wc-block-components-notice-banner" data-wp-init="callbacks.scrollIntoView" data-wp-class--is-error="state.isError" data-wp-class--is-success="state.isSuccess" data-wp-class--is-info="state.isInfo" data-wp-class--is-dismissible="context.notice.dismissible" data-wp-bind--role="state.role" data-wp-watch="callbacks.injectIcon" > <div class="wc-block-components-notice-banner__content"> <span data-wp-init="callbacks.renderNoticeContent" aria-live="assertive" aria-atomic="true"></span> </div> <button data-wp-bind--hidden="!context.notice.dismissible" class="wc-block-components-button wp-element-button wc-block-components-notice-banner__dismiss contained" aria-label="Désactiver cette notification" data-wp-on--click="actions.removeNotice" data-no-translation-aria-label="" > <svg xmlns="http://www.w3.org/2000/svg" viewbox="0 0 24 24"> <path d="M13 11.8l6.1-6.3-1-1-6.1 6.2-6.1-6.2-1 1 6.1 6.3-6.5 6.7 1 1 6.5-6.6 6.5 6.6 1-1z" /> </svg> </button> </div> </template> </div> <div data-block-name="woocommerce/product-collection-no-results" class="wp-block-woocommerce-product-collection-no-results"><div class="wp-block-group is-vertical is-content-justification-center is-layout-flex wp-container-core-group-is-layout-3c957fdc wp-block-group-is-layout-flex"> <p class="has-medium-font-size wp-block-paragraph"><strong>Aucun résultat trouvé</strong></p> <p class="wp-block-paragraph">Vous pouvez essayer <a class="wc-link-clear-any-filters" href="https://fivemx.com/fr/how-to-create-a-custom-fivem-loading-screen/">effacer tous les filtres</a> ou rendez-vous sur notre <a class="wc-link-stores-home" href="https://fivemx.com/fr/">maison du magasin</a></p> </div></div></div> <hr class="wp-block-separator has-alpha-channel-opacity" /> <h3 class="wp-block-heading" id="f">Écrans de chargement gratuits</h3> <div class="wp-block-query is-layout-flow wp-block-query-is-layout-flow"></div> <hr class="wp-block-separator has-alpha-channel-opacity" /> <p class="wp-block-paragraph">Terminé ! Des questions ? Laissez un commentaire.</p> <!-- fivemx-loading-screen-consolidation:2026-07-19 --> <section data-fivemx-content-consolidation="loading-screen-2026-07-19"> <h2>Gardez les actifs de l'écran de chargement légers</h2> <ul> <li>Compressez les images de fond et les fichiers audio avant de les emballer. Évitez une grande vidéo en lecture automatique à moins qu'elle ne soit essentielle à la conception, car chaque joueur connecté doit charger l'actif.</li> <li>Utilisez des chemins relatifs à la ressource et faites correspondre exactement la casse des noms de fichiers. Vérifiez que chaque fichier référencé par HTML, CSS et JavaScript est inclus par le manifeste des ressources.</li> <li>Définissez des dimensions d'image explicites pour éviter les déplacements de mise en page et supprimez les polices, scripts et médias inutilisés. Ne dépendez pas d'un actif distant qui peut retarder ou briser l'écran lorsque son hôte est indisponible.</li> <li>Testez avec un cache client propre et une connexion limitée. Vérifiez la console client pour les fichiers manquants, puis reconnectez-vous après un redémarrage des ressources avant de publier le changement.</li> </ul> </section> <!-- fivemx-internal-link-opportunity:2026-08-04:start --> <section class="fivemx-related-resources" data-fivemx-internal-link-opportunity="loading-screen"> <h2>Comparez un écran de chargement prêt à l'emploi</h2> <p>Si vous préférez comparer la construction personnalisée ci-dessus avec une option préemballée, consultez la <a href="/fr/ecran-de-chargement-de-codem-venice/">Écran de chargement Venice</a>. Sa page produit liste les thèmes saisonniers NUI et l'intégration de la sélection de personnages; vérifiez le support des ressources et des packs d'actifs requis sur le serveur de staging.</p> </section> <!-- fivemx-internal-link-opportunity:2026-08-04:end --> </div><!-- .entry-content --> <aside class="entry-meta"> <div class="vcard author"> <div class="avatar"></div><div class="author-details"><a href="https://fivemx.com/fr/author/fivem/" class="url fn" rel="author">Luc</a>Je m'appelle Luke, je suis un joueur et j'adore écrire sur FiveM, GTA et le jeu de rôle. Je dirige une communauté de jeu de rôle et j'ai environ 10 ans d'expérience dans l'administration de serveurs.</div> </div> <div class="post-meta"> <div class="cat-links"> <div class="label" data-no-translation="" data-trp-gettext="">Posted in:</div><a href="https://fivemx.com/fr/tutoriels-2/" rel="category tag">Tutoriels et guides</a>, <a href="https://fivemx.com/fr/script-lua/" rel="category tag">Script LUA</a> </div> <div class="tags-links"> <div class="label" data-no-translation="" data-trp-gettext="">Tagged:</div><a href="https://fivemx.com/fr/etiqueter-2/fivem-script/" rel="tag">Script fivem</a>, <a href="https://fivemx.com/fr/etiqueter-2/chargement/" rel="tag">chargement</a> </div> </div> </aside> <div class="shoptimizer-posts-prev-next"> <div class="previous-post"> <div class="title" data-no-translation="" data-trp-gettext="">Previous article</div> <a href="https://fivemx.com/fr/comment-creer-une-auto-ecole-fivem/" rel="prev">Comment créer une auto-école FiveM</a> </div> <div class="next-post"> <div class="title" data-no-translation="" data-trp-gettext="">Next article</div> <a href="https://fivemx.com/fr/tutoriel-de-monetisation-fivem/" rel="next">Guide de monétisation des serveurs FiveM</a> </div> </div> <section id="comments" class="comments-area" aria-label="Post Comments" data-no-translation-aria-label=""> <div id="respond" class="comment-respond"> <span id="reply-title" class="gamma comment-reply-title">Laisser un commentaire <small><a rel="nofollow" id="cancel-comment-reply-link" href="/fr/how-to-create-a-custom-fivem-loading-screen/#respond" style="display:none;" data-no-translation="" data-trp-gettext="">Annuler la réponse</a></small></span><p class="must-log-in" data-no-translation="" data-trp-gettext="">Vous devez <a href="https://fivemx.com/wp-login.php?redirect_to=https%3A%2F%2Ffivemx.com%2Ffr%2Fcomment-creer-un-ecran-de-chargement-fivem-personnalise%2F">vous connecter</a> pour publier un commentaire.</p> </div><!-- #respond --> </section><!-- #comments --> </div><!-- #post-## --> </main><!-- #main --> </div><!-- #primary --> </div><!-- .col-full --> </div><!-- #content --> </div> <footer class="site-footer"> <div class="col-full"> <div id="text-5" class="widget widget_text"><span class="gamma widget-title">FiveMX</span> <div class="textwidget"><p>Scripts FiveM, MLOs, packs serveur et outils avec des détails clairs sur les produits, un paiement sécurisé et un support basé sur le compte.</p> <p><a href="https://fivemx.com/fr/boutique/">Parcourir la boutique</a> · <a href="https://fivemx.com/fr/soutien/">Obtenir de l'aide</a></p> </div> </div><div id="nav_menu-19" class="widget widget_nav_menu"><span class="gamma widget-title">Cadres</span><div class="menu-fivemx-shop-frameworks-container"><ul id="menu-fivemx-shop-frameworks" class="menu"><li id="menu-item-208815" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208815"><a href="https://fivemx.com/fr/scripts-esx/">ESX</a></li> <li id="menu-item-208816" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208816"><a href="https://fivemx.com/fr/scripts-qbcore/">QB-Core</a></li> <li id="menu-item-208817" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208817"><a href="https://fivemx.com/fr/scripts-qbox/">QBOX</a></li> <li id="menu-item-208818" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208818"><a href="https://fivemx.com/fr/scripts-autonomes-2/">Standalone</a></li> </ul></div></div><div id="nav_menu-20" class="widget widget_nav_menu"><span class="gamma widget-title">Catégories</span><div class="menu-fivemx-shop-categories-container"><ul id="menu-fivemx-shop-categories" class="menu"><li id="menu-item-208293" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208293"><a href="https://fivemx.com/fr/police-scripts/">Police</a></li> <li id="menu-item-208296" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208296"><a href="https://fivemx.com/fr/scripts-de-travail-fivem/">Emplois</a></li> <li id="menu-item-208297" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208297"><a href="https://fivemx.com/fr/hud-fivem/">HUD</a></li> <li id="menu-item-208298" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208298"><a href="https://fivemx.com/fr/scripts-dinventaire-fivem/">Inventaire</a></li> <li id="menu-item-208299" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208299"><a href="https://fivemx.com/fr/fivem-mlos/">MLOs</a></li> <li id="menu-item-208300" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208300"><a href="https://fivemx.com/fr/voitures-fivem/">Véhicules</a></li> <li id="menu-item-208301" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208301"><a href="https://fivemx.com/fr/serveurs-fivem-paquets/">Packs serveur</a></li> </ul></div></div><div id="nav_menu-10" class="widget widget_nav_menu"><span class="gamma widget-title">Aide et mentions légales</span><div class="menu-footer-terms-container"><ul id="menu-footer-terms" class="menu"><li id="menu-item-808" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-808"><a href="https://fivemx.com/fr/conditions-generales/">Termes et conditions</a></li> <li id="menu-item-810" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-810"><a href="https://fivemx.com/fr/garantie/">Politique de remboursement</a></li> <li id="menu-item-809" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-809"><a href="https://fivemx.com/fr/politique-de-confidentialite/">politique de confidentialité</a></li> <li id="menu-item-214468" class="menu-item menu-item-type-post_type menu-item-object-page menu-item-214468"><a href="https://fivemx.com/fr/a-propos/">À propos de FiveMX<div class="icon-wrapper"> </div></a></li> <li id="menu-item-208589" class="menu-item menu-item-type-custom menu-item-object-custom menu-item-208589"><a href="https://fivemx.com/fr/contact/">Contact</a></li> </ul></div></div> </div> </footer> <footer class="copyright"> <div class="col-full"> <div id="custom_html-7" class="widget_text widget widget_custom_html"><div class="textwidget custom-html-widget">© 2026 FiveMX. Tous droits réservés.</div></div> </div> </footer> </div><!-- #page --> <script id="fivemx-tawk-layout-stability"> (() => { const styleId = 'fivemx-tawk-emoji-layout'; const watched = new WeakSet(); let footerVisible = false; let purchaseControlsVisible = false; const extendedObserverRelease = Date.parse('2026-07-26T06:30:00Z'); const observerLifetime = Date.now() >= extendedObserverRelease ? 60000 : 15000; const mobilePurchaseViewport = window.matchMedia('(max-width: 1024px)'); const mobileStorefront = window.matchMedia('(max-width: 1024px)').matches && ( document.body.classList.contains('home') || document.body.classList.contains('single-product') || document.body.classList.contains('post-type-archive-product') || document.body.classList.contains('tax-product_cat') || document.body.classList.contains('tax-product_tag') ); const isTawkFrame = (frame) => { if (!(frame instanceof HTMLIFrameElement) || frame.parentElement?.parentElement !== document.body) { return false; } const layer = Number.parseInt(frame.style.zIndex || '0', 10); const fixed = frame.style.position === 'fixed'; const rootLayer = Number.parseInt( frame.parentElement.style.zIndex || window.getComputedStyle(frame.parentElement).zIndex || '0', 10 ); const fixedRoot = window.getComputedStyle(frame.parentElement).position === 'fixed'; if ((fixed && layer >= 1000002) || (fixedRoot && rootLayer >= 1000002)) { frame.parentElement.dataset.fivemxTawkRoot = 'true'; } return frame.parentElement.dataset.fivemxTawkRoot === 'true'; }; const syncChatVisibility = (frame) => { if (!isTawkFrame(frame)) return; const hideChat = document.body.classList.contains('drawer-open') || footerVisible || purchaseControlsVisible; const visibility = hideChat ? 'hidden' : 'visible'; const pointerEvents = hideChat ? 'none' : 'auto'; if ( frame.style.getPropertyValue('visibility') !== visibility || frame.style.getPropertyPriority('visibility') !== 'important' ) { frame.style.setProperty('visibility', visibility, 'important'); } if ( frame.style.getPropertyValue('pointer-events') !== pointerEvents || frame.style.getPropertyPriority('pointer-events') !== 'important' ) { frame.style.setProperty('pointer-events', pointerEvents, 'important'); } }; const patchFrame = (frame) => { const label = () => { if (isTawkFrame(frame) && !frame.hasAttribute('title')) { frame.setAttribute('title', 'FiveMX live chat'); } }; const suppressMobileAttentionGrabber = () => { if (!mobileStorefront || !isTawkFrame(frame)) return; const width = Number.parseFloat(frame.style.width || '0'); const height = Number.parseFloat(frame.style.height || '0'); const layer = Number.parseInt(frame.style.zIndex || '0', 10); const isAttentionImage = width === 124 && height === 95 && layer === 1000004; const isMessagePreview = width >= 300 && height >= 150 && height <= 400 && (frame.style.zIndex === '' || frame.style.zIndex === 'auto'); if ((isAttentionImage || isMessagePreview) && frame.style.display !== 'none') { frame.style.setProperty('display', 'none', 'important'); } }; label(); suppressMobileAttentionGrabber(); syncChatVisibility(frame); if (watched.has(frame)) return; watched.add(frame); const patch = () => { label(); suppressMobileAttentionGrabber(); try { const doc = frame.contentDocument; if (!doc || !doc.head) return false; if (doc.getElementById(styleId)) return true; const style = doc.createElement('style'); style.id = styleId; style.textContent = 'img.emojione{width:16px!important;height:16px!important;}'; doc.head.appendChild(style); return true; } catch (_) { return true; } }; patch(); frame.addEventListener('load', patch, { passive: true }); }; const inspect = (node) => { if (!(node instanceof Element)) return; if (node.matches('iframe')) patchFrame(node); node.querySelectorAll('iframe').forEach(patchFrame); }; document.querySelectorAll('iframe').forEach(patchFrame); const observer = new MutationObserver((records) => { records.forEach((record) => { if (record.type === 'attributes') { inspect(record.target); return; } record.addedNodes.forEach(inspect); }); }); observer.observe(document.documentElement, { attributes: true, attributeFilter: ['src', 'style'], childList: true, subtree: true, }); const drawerObserver = new MutationObserver(() => { document.querySelectorAll('iframe').forEach(syncChatVisibility); }); drawerObserver.observe(document.body, { attributes: true, attributeFilter: ['class'], }); const footer = document.querySelector('.site-footer'); if (footer && 'IntersectionObserver' in window) { const footerObserver = new IntersectionObserver((entries) => { footerVisible = entries.some((entry) => entry.isIntersecting); document.querySelectorAll('iframe').forEach(syncChatVisibility); }, { threshold: 0.01 }); footerObserver.observe(footer); } const purchaseControls = document.querySelectorAll( 'body.single-product .summary, body.woocommerce-cart .wc-proceed-to-checkout' ); if (purchaseControls.length && mobilePurchaseViewport.matches && 'IntersectionObserver' in window) { const visiblePurchaseControls = new Set(); const purchaseObserver = new IntersectionObserver((entries) => { entries.forEach((entry) => { if (entry.isIntersecting) { visiblePurchaseControls.add(entry.target); } else { visiblePurchaseControls.delete(entry.target); } }); purchaseControlsVisible = visiblePurchaseControls.size > 0; document.querySelectorAll('iframe').forEach(syncChatVisibility); }, { threshold: 0.01 }); purchaseControls.forEach((control) => purchaseObserver.observe(control)); } window.setTimeout(() => observer.disconnect(), observerLifetime); })(); </script> <template id="tp-language" data-tp-language="fr_FR"></template><script type="speculationrules"> {"prefetch":[{"source":"document","where":{"and":[{"href_matches":"/fr/*"},{"not":{"href_matches":["/wp-*.php","/wp-admin/*","/wp-content/uploads/*","/wp-content/*","/wp-content/plugins/*","/wp-content/themes/shoptimizer/*","/fr/*\\?(.+)","/fr/checkout/","/fr/cart/"]}},{"not":{"selector_matches":"a[rel~=\"nofollow\"]"}},{"not":{"selector_matches":".no-prefetch, .no-prefetch a"}}]},"eagerness":"conservative"}]} </script> <input type="hidden" id="commercekit_nonce" name="commercekit_nonce" value="ea8e646b8e" /><input type="hidden" name="_wp_http_referer" value="/fr/how-to-create-a-custom-fivem-loading-screen/" /><script type="text/javascript"> /* <![CDATA[ */ document.addEventListener( 'DOMContentLoaded', function() { var cgkit_nonce_ustate = 0; var cgkit_nonce_cvalue = Cookies.get( 'commercekit-nonce-value' ); var cgkit_nonce_cstate = Cookies.get( 'commercekit-nonce-state' ); var cgkit_user_switched = 0; var cgkit_fast_token = Cookies.get( 'commercekit-fast-token' ); cgkit_nonce_cvalue = cgkit_nonce_cvalue !== undefined ? cgkit_nonce_cvalue : ''; cgkit_fast_token = cgkit_fast_token !== undefined ? cgkit_fast_token : ''; if ( cgkit_nonce_cvalue == '' || cgkit_nonce_cstate != cgkit_nonce_ustate || cgkit_user_switched == 1 || ( cgkit_fast_token == '' && commercekit_ajs.fast_ajax_search !== undefined && commercekit_ajs.fast_ajax_search == 1 ) ) { var timestamp = new Date().getTime(); fetch( commercekit_ajs.ajax_url + '=commercekit_get_nonce&v=' + timestamp, { method: 'GET', } ).then( response => response.json() ).then( json => { if ( json.status == 1 ) { var twohrs = new Date( new Date().getTime() + 120 * 60 * 1000 ); if ( window.Cookiebot ) { /* Cookiebot compatible */ if ( window.Cookiebot.consent.preferences || window.Cookiebot.consent.statistics || window.Cookiebot.consent.marketing ) { Cookies.set( 'commercekit-nonce-value', json.nonce, { expires: twohrs } ); Cookies.set( 'commercekit-nonce-state', json.state, { expires: twohrs } ); if ( json.fast_token != '' ) { Cookies.set( 'commercekit-fast-token', json.fast_token, { expires: twohrs } ); } } else { Cookies.remove( 'commercekit-nonce-value' ); Cookies.remove( 'commercekit-nonce-state' ); Cookies.remove( 'commercekit-fast-token' ); } } else { Cookies.set( 'commercekit-nonce-value', json.nonce, { expires: twohrs } ); Cookies.set( 'commercekit-nonce-state', json.state, { expires: twohrs } ); if ( json.fast_token != '' ) { Cookies.set( 'commercekit-fast-token', json.fast_token, { expires: twohrs } ); } } cgkit_nonce_ustate = json.state; commercekit_update_nonce( json.nonce ); } } ); } else { commercekit_update_nonce( cgkit_nonce_cvalue ); } } ); function commercekit_update_nonce( nonce ) { var nonce_input = document.querySelector( '#commercekit_nonce' ); if ( nonce_input ) { nonce_input.value = nonce; } else { document.body.insertAdjacentHTML( 'beforeend', '<' + 'input type="hidden" id="commercekit_nonce" name="commercekit_nonce" value="' + nonce + '"' + '>' ); } commercekit_ajs.ajax_nonce = 1; if ( typeof cgkit_update_order_bump_views == 'function' ) { cgkit_update_order_bump_views(); } } /* ]]> */ </script> <script type="text/javascript"> /* <![CDATA[ */ var cgkit_wbmc = document.querySelector( '.wc-block-mini-cart' ); if ( cgkit_wbmc ) { var cgkitMCBCurrentRequest = null; var cgkitMCBCurrentCancel = null; function cgkitLoadMiniCartBlocks() { var cgkit_drawer = document.querySelector( '.wc-block-mini-cart__drawer' ); if ( ! cgkit_drawer ) { return; } clearTimeout( cgkitMCBCurrentRequest ); cgkitMCBCurrentRequest = setTimeout( function() { if ( cgkitMCBCurrentCancel ) { cgkitMCBCurrentCancel.abort(); } cgkitMCBCurrentCancel = new AbortController(); var timestamp = new Date().getTime(); fetch( commercekit_ajs.ajax_url + '=commercekit_mini_cart_blocks&v=' + timestamp, { signal: cgkitMCBCurrentCancel.signal, method: 'GET', } ).then( response => response.json() ).then( json => { if ( json.success ) { var cgkit_table = document.querySelector( '.wc-block-mini-cart__drawer .wc-block-mini-cart__items' ); var cgkit_before = document.querySelector( '#cgkit-before-mini-cart-blocks' ); if ( cgkit_before ) { cgkit_before.innerHTML = json.data.before_cart; } else if ( cgkit_table ) { cgkit_table.insertAdjacentHTML( 'afterbegin', '<div id="cgkit-before-mini-cart-blocks">' + json.data.before_cart + '</div>' ); } var cgkit_after = document.querySelector( '#cgkit-after-mini-cart-blocks' ); if ( cgkit_after ) { cgkit_after.innerHTML = json.data.after_cart; } else if ( cgkit_table ) { cgkit_table.insertAdjacentHTML( 'beforeend', '<div id="cgkit-after-mini-cart-blocks">' + json.data.after_cart + '</div>' ); } } } ).catch( function( e ) { } ); }, 100 ); } document.addEventListener( 'click', function( e ) { $this = e.target; $thisp = $this.closest( '.wc-block-mini-cart' ); if ( $this.classList.contains( 'wc-block-mini-cart' ) || $thisp ) { setTimeout( function() { cgkitLoadMiniCartBlocks(); }, 500 ); } } ); ( function() { const originalFetch = window.fetch; window.fetch = async function(...args) { const response = await originalFetch(...args); if ( args[0].includes( '/wc/store/v1/batch' ) || args[0].includes( '/wc/store/v1/cart' ) ) { cgkitLoadMiniCartBlocks(); } return response; }; } )(); } var cgkit_wbc = document.querySelector( '.wp-block-woocommerce-cart' ); if ( cgkit_wbc ) { var cgkit_wbc_timer = null; var cgkit_wbc_observer = new MutationObserver( function( mutations ) { clearTimeout( cgkit_wbc_timer ); cgkit_wbc_timer = setTimeout( function() { cgkit_update_wc_cart_block_fragments(); }, 100 ); } ); cgkit_wbc_observer.observe( cgkit_wbc, { childList: true, subtree: true} ); } function cgkit_update_wc_cart_block_fragments() { var ucfragment = new Event( 'wc_fragment_refresh' ); document.body.dispatchEvent( ucfragment ); } /* ]]> */ </script> <script type="text/javascript"> function commercekitOrderBumpAdd(product_id, obj, position){ var ajax_nonce = ''; var is_block_checkout = typeof window.cgkitBlockObpNonce !== 'undefined'; if ( is_block_checkout ) { ajax_nonce = window.cgkitBlockObpNonce; } else if ( commercekit_ajs.ajax_nonce != 1 ) { return true; } else { var nonce_input = document.querySelector( '#commercekit_nonce' ); if ( nonce_input ) { ajax_nonce = nonce_input.value; } } obj.setAttribute('disabled', 'disabled'); var wrap = obj.closest('.commercekit-order-bump-wrap'); if( wrap ){ var bullets = wrap.querySelector('.ckobp-bullets'); if( bullets ){ bullets.classList.add('processing'); } } var formData = new FormData(); formData.append('product_id', product_id); formData.append('commercekit_nonce', ajax_nonce); fetch( commercekit_ajs.ajax_url + '=commercekit_order_bump_add', { method: 'POST', body: formData, }).then(response => response.json()).then( json => { var ppp = document.querySelector('.paypalplus-paywall'); var wooccm = document.querySelectorAll('form.woocommerce-checkout .wooccm-field'); if ( is_block_checkout ) { if ( window.wp && window.wp.data ) { window.wp.data.dispatch('wc/store/cart').invalidateResolutionForStoreSelector('getCartData'); window.wp.data.dispatch('wc/store/cart').invalidateResolutionForStoreSelector('getCartTotals'); } if ( typeof window.cgkitRefreshBlockOrderBump === 'function' ) { window.cgkitRefreshBlockOrderBump( ajax_nonce ); } } else if ( ppp || wooccm.length > 0 ) { window.location.reload(); } else { var ucheckout = new Event('update_checkout'); document.body.dispatchEvent(ucheckout); var ufragment = new Event('wc_fragment_refresh'); document.body.dispatchEvent(ufragment); var cgkit_cart_drawer = document.querySelector( '.wc-block-mini-cart__drawer' ); if ( cgkit_cart_drawer ) { jQuery(document.body).trigger('added_to_cart'); if ( typeof cgkitLoadMiniCartBlocks == 'function' ) { cgkitLoadMiniCartBlocks(); } } } }); } var ckit_obp_clicked = false; var ckit_obp_clicked_id = 0; document.addEventListener('click', function(e){ $this = e.target; if( $this.classList.contains( 'ckobp-bullet' ) ) { e.preventDefault(); e.stopPropagation(); ckit_obp_clicked = true; ckit_obp_make_active($this, true); if( ckit_obp_clicked_id ){ clearTimeout( ckit_obp_clicked_id ); } ckit_obp_clicked_id = setTimeout(function(){ ckit_obp_clicked = false; ckit_obp_clicked_id = 0; }, 1000); } $thisp = $this.closest('.ckobp-prev'); if( $this.classList.contains( 'ckobp-prev' ) || $thisp ) { e.preventDefault(); e.stopPropagation(); var parent = $this.closest( '.commercekit-order-bump-wrap' ); var par_divs = parent.querySelector('.ckobp-bullets'); var $is_rtl = document.querySelector('body.rtl'); if( par_divs ){ var $index = parseInt(par_divs.getAttribute('data-index')); if( $index == 1 && ! $is_rtl ){ return true; } var $nindex = $is_rtl ? $index + 1 : $index - 1; var $bullet = parent.querySelector('.ckobp-bullets .ckobp-bullet[data-index="'+$nindex+'"]'); if( $bullet ){ $bullet.click(); } } } $thisp = $this.closest('.ckobp-next'); if( $this.classList.contains( 'ckobp-next' ) || $thisp ) { e.preventDefault(); e.stopPropagation(); var parent = $this.closest( '.commercekit-order-bump-wrap' ); var par_divs = parent.querySelector('.ckobp-bullets'); var $is_rtl = document.querySelector('body.rtl'); if( par_divs ){ var total = parseInt(par_divs.getAttribute('data-total')); var $index = parseInt(par_divs.getAttribute('data-index')); if( $index == total && ! $is_rtl ){ return true; } var $nindex = $is_rtl ? $index - 1 : $index + 1; var $bullet = parent.querySelector('.ckobp-bullets .ckobp-bullet[data-index="'+$nindex+'"]'); if( $bullet ){ $bullet.click(); } } } }); function ckit_obp_make_active($this, $scroll){ var parent = $this.closest( '.commercekit-order-bump-wrap' ); var $id = $this.getAttribute( 'id' ).replace( 'bullet-', '' ); var $mthis = parent.querySelector( '#' + $id ); var main_divs = parent.querySelectorAll('.commercekit-order-bumps .commercekit-order-bump'); $this.classList.add( 'active' ); $mthis.classList.add( 'active' ); main_divs.forEach(function(main_div){ if( main_div !== $mthis ){ main_div.classList.remove( 'active' ); } }); var sub_divs = parent.querySelectorAll('.ckobp-bullets .ckobp-bullet'); sub_divs.forEach(function(sub_divs){ if( sub_divs !== $this ){ sub_divs.classList.remove( 'active' ); } }); var $index = parseInt($mthis.getAttribute('data-index')); var par_divs = parent.querySelector('.ckobp-bullets'); if( par_divs ){ var total = parseInt(par_divs.getAttribute('data-total')); par_divs.setAttribute('data-index', $index); ckit_obp_update_prev_next(parent, total, $index); } if( $scroll ){ var $width = $mthis.clientWidth; var $scroll_left = ( $index - 1 ) * $width; var $is_rtl = document.querySelector('body.rtl'); if( $is_rtl ){ $scroll_left = -$scroll_left; } var ckit_obps = parent.querySelector('.commercekit-order-bumps'); if( ckit_obps ){ ckit_obps.scroll({ left: $scroll_left, top: 0, behavior: 'smooth' }); } } } document.addEventListener('scroll', function(e){ var $this = e.target; if( $this.classList && $this.classList.contains('commercekit-order-bumps') && !ckit_obp_clicked ){ var sub_div = $this.querySelector('.commercekit-order-bump:first-child'); if( sub_div ){ var parent = $this.closest( '.commercekit-order-bump-wrap' ); var $width = sub_div.clientWidth; var $scroll_left = Math.abs($this.scrollLeft); var $index = Math.round( $scroll_left / $width ) + 1; var $bullet = parent.querySelector('.ckobp-bullets .ckobp-bullet[data-index="'+$index+'"]'); if( $bullet ){ ckit_obp_make_active($bullet, false); } } } }, true); function ckit_obp_update_prev_next(parent, total, $index){ var prev = parent.querySelector('.ckobp-prev'); var next = parent.querySelector('.ckobp-next'); if( prev && next ){ next.classList.remove('ckobp-disabled'); prev.classList.remove('ckobp-disabled'); var $is_rtl = document.querySelector('body.rtl'); if( $is_rtl ){ if( $index == 1 ) { next.classList.add('ckobp-disabled'); } if( $index == total ) { prev.classList.add('ckobp-disabled'); } } else { if( $index == 1 ) { prev.classList.add('ckobp-disabled'); } if( $index == total ) { next.classList.add('ckobp-disabled'); } } } } document.addEventListener('keypress', function(e) { var active_elm = document.activeElement; if( active_elm && e.key == 'Enter' && ( active_elm.classList.contains('ckobp-prev') || active_elm.classList.contains('ckobp-next') ) ) { active_elm.click(); } }); var cgkit_updating_obp_views = false; function cgkit_update_order_bump_views() { var product_ids = []; var cgkit_obps = document.querySelectorAll( 'div.commercekit-order-bump[data-product-id]' ); if ( cgkit_obps.length > 0 ) { cgkit_obps.forEach( function( cgkit_obp ) { product_ids.push( cgkit_obp.getAttribute( 'data-product-id' ) ); } ); } if ( product_ids.length == 0 ) { return; } if ( cgkit_updating_obp_views ) { return; } var viewed = decodeURIComponent( document.cookie.match( /commercekit_obp_view_ids=([^;]+)/ ) ); viewed = viewed.replace( 'commercekit_obp_view_ids=', '' ); var viewedIds = viewed ? viewed.split(',') : []; var newIds = product_ids.filter( function( id ) { return viewedIds.indexOf( id ) === -1; } ); if ( newIds.length === 0 ) { return; } var ajax_nonce = ''; var nonce_input = document.querySelector( '#commercekit_nonce' ); if ( nonce_input ) { ajax_nonce = nonce_input.value; } var formData = new FormData(); formData.append( 'product_ids', product_ids ); formData.append( 'commercekit_nonce', ajax_nonce ); cgkit_updating_obp_views = true; fetch( commercekit_ajs.ajax_url + '=commercekit_orderbump_views', { method: 'POST', body: formData, } ).then( response => response.json() ).then( json => { cgkit_updating_obp_views = false; } ); } document.addEventListener( 'DOMContentLoaded', function() { if ( jQuery ) { jQuery( document ).on( 'wc_fragments_loaded wc_fragments_refreshed', function() { cgkit_update_order_bump_views(); } ); } } ); function cgkit_obp_toggle_selecter( obj ) { var wrap = obj.closest( '.commercekit-order-bump' ); if ( wrap ) { var obp_sel = wrap.querySelector('.cgkit-order-bump-selector'); if ( obp_sel ) { obp_sel.classList.toggle( 'active' ); } } } document.addEventListener( 'DOMContentLoaded', function() { document.addEventListener( 'click', function( event ) { if( ! event.target.classList.contains( 'cgkit-order-bump-clear' ) ) { return; } event.preventDefault(); event.stopPropagation(); var wrap = event.target.closest( '.cgkit-order-bump-selector' ); var wrap2 = event.target.closest( '.commercekit-order-bump' ); if( ! wrap || ! wrap2 ) { return; } var selects = wrap.querySelectorAll( '.cgkit-order-bump-attribute' ); selects.forEach( sel => { sel.value = ''; } ); if ( selects.length > 0 ) { var event_object = new Event( 'change', { bubbles: true } ); selects[0].dispatchEvent( event_object ); } wrap.setAttribute( 'data-gimg_id', '' ); cgkit_update_obp_selecter_image( wrap2 ); } ); document.addEventListener( 'change', function( event ) { if( ! event.target.classList.contains( 'cgkit-order-bump-attribute' ) ) { return; } var wrap = event.target.closest( '.cgkit-order-bump-selector' ); var wrap2 = event.target.closest( '.commercekit-order-bump' ); if( ! wrap || ! wrap2 ) { return; } var variations = wrap.dataset.variations ? JSON.parse( wrap.dataset.variations ) : []; var status_box = wrap.querySelector('.cgkit-order-bump-status'); var atc_btn = wrap2.querySelector('.cgkit-order-bump-atc'); var price_div = wrap2.querySelector('.ckobp-price'); if( ! status_box || ! atc_btn || ! price_div ) { return; } var original_price = price_div.getAttribute('data-price'); if( ! original_price ){ original_price = price_div.innerHTML; price_div.setAttribute('data-price', price_div.innerHTML); } var $select = event.target; var selected_option = $select.selectedOptions[0]; var gimg_id = selected_option.getAttribute( 'data-gimg_id' ); var selected = {}; var attr_count = 0; var select_count = 0; wrap.querySelectorAll( '.cgkit-order-bump-attribute' ).forEach( sel => { attr_count++; var attr_name = sel.dataset.attributeName; var value = sel.value; if ( value ) { select_count++; if ( attr_name.indexOf( 'attribute_' ) !== 0 ){ attr_name = 'attribute_' + attr_name; } selected[attr_name] = value; } } ); if ( attr_count != select_count ) { price_div.innerHTML = original_price; atc_btn.textContent = atc_btn.dataset.selectText; atc_btn.setAttribute( 'onclick', 'cgkit_obp_toggle_selecter(this);' ); status_box.textContent = ''; wrap.setAttribute( 'data-gimg_id', '' ); cgkit_update_obp_selecter_image( wrap2 ); return; } var matching = variations.find( v => { var ok = true; for ( var key in v.attributes ) { if ( ! selected[key] || selected[key] !== v.attributes[key] ) { ok = false; break; } } return ok; } ); if ( ! matching ) { price_div.innerHTML = original_price; atc_btn.textContent = atc_btn.dataset.selectText; atc_btn.setAttribute( 'onclick', 'cgkit_obp_toggle_selecter(this);' ); status_box.textContent = atc_btn.dataset.naText; wrap.setAttribute( 'data-gimg_id', '' ); cgkit_update_obp_selecter_image( wrap2 ); return; } if ( ! matching.is_in_stock ) { price_div.innerHTML = matching.price_html; atc_btn.textContent = atc_btn.dataset.selectText; atc_btn.setAttribute( 'onclick', 'cgkit_obp_toggle_selecter(this);' ); status_box.textContent = atc_btn.dataset.oosText; wrap.setAttribute( 'data-gimg_id', matching.cgkit_image_id ); cgkit_update_obp_selecter_image( wrap2 ); return; } if ( ! matching.is_purchasable ) { price_div.innerHTML = matching.price_html; atc_btn.textContent = atc_btn.dataset.selectText; atc_btn.setAttribute( 'onclick', 'cgkit_obp_toggle_selecter(this);' ); status_box.textContent = atc_btn.dataset.naText; wrap.setAttribute( 'data-gimg_id', matching.cgkit_image_id ); cgkit_update_obp_selecter_image( wrap2 ); return; } atc_btn.textContent = atc_btn.dataset.atcText; atc_btn.setAttribute( 'onclick', "commercekitOrderBumpAdd(" + matching.variation_id + ", this, '" + atc_btn.dataset.position + "');" ); status_box.textContent = ''; price_div.innerHTML = matching.price_html; wrap.setAttribute( 'data-gimg_id', matching.cgkit_image_id ); cgkit_update_obp_selecter_image( wrap2 ); } ); } ); function cgkit_update_obp_selecter_image( wrap ) { var attr_count = 0; var empty_count = 0; var select_count = 0; var gimg_id = ''; wrap.querySelectorAll( '.cgkit-order-bump-attribute' ).forEach( sel => { attr_count++; if ( sel.value == '' ) { empty_count++; } else { select_count++; } var selected_option = sel.selectedOptions[0]; var sel_img_id = selected_option.getAttribute( 'data-gimg_id' ); if ( sel_img_id != '' ) { gimg_id = sel_img_id; } } ); var clr_btn = wrap.querySelector( '.cgkit-obp-status-wrap' ); if ( clr_btn ) { if ( attr_count == empty_count ) { clr_btn.style.display = 'none'; } else { clr_btn.style.display = ''; } } var wrap2 = wrap.querySelector( '.cgkit-order-bump-selector' ); if ( ! wrap2 ) { return; } var images = JSON.parse( wrap2.getAttribute( 'data-images' ) ); if ( ! images || Object.keys( images ).length == 0 ) { return; } var img_img = wrap.querySelector( '.ckobp-image img' ); if ( ! img_img ) { return; } var vimg_id = wrap2.getAttribute( 'data-gimg_id' ); if ( select_count == attr_count && vimg_id != '' ) { gimg_id = vimg_id; } if ( gimg_id != '' && images.hasOwnProperty( 'img_' + gimg_id ) ) { var img_key = 'img_' + gimg_id; var img_src = img_img.getAttribute( 'data-obp-src' ); if ( ! img_src ) { img_img.setAttribute( 'data-obp-src', img_img.getAttribute( 'src' ) ); img_img.setAttribute( 'data-obp-srcset', '' ); img_img.setAttribute( 'data-obp-sizes', '' ); var img_srcset = img_img.getAttribute( 'srcset' ); var img_sizes = img_img.getAttribute( 'sizes' ); if ( img_srcset ) { img_img.setAttribute( 'data-obp-srcset', img_srcset ); } if ( img_sizes ) { img_img.setAttribute( 'data-obp-sizes', img_sizes ); } } if ( images[img_key].srcset ) { img_img.setAttribute( 'srcset', images[img_key].srcset ); } else { img_img.setAttribute( 'srcset', '' ); } if ( images[img_key].sizes ) { img_img.setAttribute( 'sizes', images[img_key].sizes ); } else { img_img.setAttribute( 'sizes', '' ); } img_img.setAttribute( 'src', images[img_key].src ); } else { var img_src = img_img.getAttribute( 'data-obp-src' ); var img_srcset = img_img.getAttribute( 'data-obp-srcset' ); var img_sizes = img_img.getAttribute( 'data-obp-sizes' ); if ( img_src ) { if ( img_srcset ) { img_img.setAttribute( 'srcset', img_srcset ); } else { img_img.setAttribute( 'srcset', '' ); } if ( img_sizes ) { img_img.setAttribute( 'sizes', img_sizes ); } else { img_img.setAttribute( 'sizes', '' ); } img_img.setAttribute( 'src', img_src ); } } } </script> <script id="wp-importmap" type="importmap"> {"imports":{"@wordpress/interactivity":"https://fivemx.com/wp-includes/js/dist/script-modules/interactivity/index.min.js?ver=efaa5193bbad9c60ffd1","@wordpress/interactivity-router":"https://fivemx.com/wp-includes/js/dist/script-modules/interactivity-router/index.min.js?ver=71aa17bac91628a0f874","@wordpress/a11y":"https://fivemx.com/wp-includes/js/dist/script-modules/a11y/index.min.js?ver=1c371cb517a97cdbcb9f"}} </script> <script id="woocommerce/product-collection-js-module" src="https://fivemx.com/wp-content/plugins/woocommerce/assets/client/blocks/woocommerce/product-collection.js?ver=892c2bfe326c817cd409" type="module"></script> <link rel="modulepreload" href="https://fivemx.com/wp-includes/js/dist/script-modules/interactivity/index.min.js?ver=efaa5193bbad9c60ffd1" id="@wordpress/interactivity-js-modulepreload" data-wp-fetchpriority="low"> <script id="wp-script-module-data-@wordpress/interactivity" type="application/json"> {"state":{"woocommerce/store-notices":{"notices":[]},"core/router":{"url":"https://fivemx.com/fr/how-to-create-a-custom-fivem-loading-screen/"}}} </script> <script id="wp-script-module-data-@wordpress/interactivity-router" type="application/json"> {"i18n":{"loading":"Chargement de la page en cours, veuillez patienter.","loaded":"Page chargée."}} </script> <script> ( () => { const lazyloadRunObserver = () => { const lazyloadBackgrounds = document.querySelectorAll( `.e-con.e-parent:not(.e-lazyloaded)` ); const lazyloadBackgroundObserver = new IntersectionObserver( ( entries ) => { entries.forEach( ( entry ) => { if ( entry.isIntersecting ) { let lazyloadBackground = entry.target; if( lazyloadBackground ) { lazyloadBackground.classList.add( 'e-lazyloaded' ); } lazyloadBackgroundObserver.unobserve( entry.target ); } }); }, { rootMargin: '200px 0px 200px 0px' } ); lazyloadBackgrounds.forEach( ( lazyloadBackground ) => { lazyloadBackgroundObserver.observe( lazyloadBackground ); } ); }; const events = [ 'DOMContentLoaded', 'elementor/lazyload/observe', ]; events.forEach( ( event ) => { document.addEventListener( event, lazyloadRunObserver ); } ); } )(); </script> <!--Start of Tawk.to Script (0.9.3)--> <script id="tawk-script" type="text/javascript"> var Tawk_API = Tawk_API || {}; var Tawk_LoadStart; (function(){ if (navigator.webdriver === true || /HeadlessChrome/i.test(navigator.userAgent)) return; var loaded = false; var events = ['pointerdown', 'keydown', 'touchstart']; var load = function(){ if (loaded) return; loaded = true; events.forEach(function(eventName){ window.removeEventListener(eventName, load); }); Tawk_LoadStart = new Date(); (function(){ var s1 = document.createElement( 'script' ),s0=document.getElementsByTagName( 'script' )[0]; s1.async = true; s1.src = 'https://embed.tawk.to/6a60f4f514d8401d499dde5f/1ju5bpnpl'; s1.charset = 'UTF-8'; s0.parentNode.insertBefore( s1, s0 ); })(); }; events.forEach(function(eventName){ window.addEventListener(eventName, load, { once: true, passive: true }); }); if ('requestIdleCallback' in window) { window.requestIdleCallback(load, { timeout: 5000 }); } else { window.setTimeout(load, 3500); } })(); </script> <!--End of Tawk.to Script (0.9.3)--> <script type='text/javascript'> (function () { var c = document.body.className; c = c.replace(/woocommerce-no-js/, 'woocommerce-js'); document.body.className = c; })(); </script> <div class="wp-interactivity-router-loading-bar" data-wp-interactive="core/router/private" data-wp-class--start-animation="state.navigation.hasStarted" data-wp-class--finish-animation="state.navigation.hasFinished" ></div><div class="fivemx-exit-popup" data-fivemx-exit-popup data-fivemx-offer-campaign="welcome-2026-07" data-dismiss-until="2026-11-17" hidden><div class="fivemx-exit-popup__backdrop" data-fivemx-exit-popup-backdrop></div><div class="fivemx-exit-popup__card" role="dialog" aria-labelledby="fivemx-exit-popup-title" tabindex="-1"><button class="fivemx-exit-popup__close" type="button" data-fivemx-exit-popup-close aria-label="Fermer l’offre" data-no-translation-aria-label="">×</button><strong class="fivemx-exit-popup__title" id="fivemx-exit-popup-title" data-no-translation="" data-trp-gettext="">Économisez 20 % avec WELCOME</strong><p class="fivemx-exit-popup__body" data-no-translation="" data-trp-gettext="">Jusqu’au 17 novembre 2026.</p><p class="fivemx-exit-popup__code"><code data-fivemx-exit-popup-code>WELCOME</code><button class="fivemx-exit-popup__copy" type="button" data-fivemx-exit-popup-copy data-copied-label="Code copié" data-fivemx-offer-action="copy_coupon" data-fivemx-offer-surface="exit_popup" data-fivemx-offer-campaign="welcome-2026-07" data-no-translation="" data-trp-gettext="" data-no-translation-data-copied-label="">Copier le code</button></p><p class="fivemx-exit-popup__link"><a href="https://fivemx.com/fr/sales/" data-fivemx-offer-action="view_sales" data-fivemx-offer-surface="exit_popup" data-fivemx-offer-campaign="welcome-2026-07" data-no-translation="" data-trp-gettext="">Voir les promotions</a></p></div></div> <script id="fivemx-exit-popup"> (function () { var popup = document.querySelector('[data-fivemx-exit-popup]'); if (!popup) { return; } // Exit intent is a pointer gesture. Touch has no equivalent, and a // popup on a small screen is an interstitial Google penalises. var isPointerDevice = window.matchMedia && window.matchMedia('(hover: hover) and (pointer: fine)').matches; if (!isPointerDevice || window.innerWidth < 1024) { return; } var cookieName = 'fivemx_exit_popup_dismissed_until'; var cookieExpires = 'Tue, 17 Nov 2026 23:00:00 GMT'; var sessionKey = 'fivemxExitPopupShown'; var storageKey = 'fivemxExitPopupDismissedUntil'; var dismissUntil = popup.getAttribute('data-dismiss-until') || ''; if (document.cookie.indexOf(cookieName + '=' + encodeURIComponent(dismissUntil)) !== -1) { return; } try { if (window.localStorage.getItem(storageKey) === dismissUntil) { return; } if (window.sessionStorage.getItem(sessionKey) === '1') { return; } } catch (error) {} var card = popup.querySelector('.fivemx-exit-popup__card'); var closeButton = popup.querySelector('[data-fivemx-exit-popup-close]'); var backdrop = popup.querySelector('[data-fivemx-exit-popup-backdrop]'); var copyButton = popup.querySelector('[data-fivemx-exit-popup-copy]'); var lastFocused = null; var isOpen = false; var readyAt = Date.now() + 5000; function focusable() { return Array.prototype.filter.call( card.querySelectorAll('a[href], button:not([disabled]), input, [tabindex]:not([tabindex="-1"])'), function (node) { return node.offsetParent !== null; } ); } function close() { if (!isOpen) { return; } isOpen = false; popup.hidden = true; card.removeAttribute('aria-modal'); document.documentElement.classList.remove('fivemx-exit-popup-open'); try { window.localStorage.setItem(storageKey, dismissUntil); } catch (error) {} document.cookie = cookieName + '=' + encodeURIComponent(dismissUntil) + '; expires=' + cookieExpires + '; path=/; SameSite=Lax'; if (lastFocused && typeof lastFocused.focus === 'function') { lastFocused.focus(); } } function open() { if (isOpen || Date.now() < readyAt) { return; } // The bar carries the same offer. Do not say it twice at once. var bar = document.querySelector('[data-fivemx-promo-bar]'); if (bar && !bar.hidden && bar.style.display !== 'none') { return; } isOpen = true; lastFocused = document.activeElement; popup.hidden = false; card.setAttribute('aria-modal', 'true'); document.documentElement.classList.add('fivemx-exit-popup-open'); card.focus(); try { window.sessionStorage.setItem(sessionKey, '1'); } catch (error) {} } document.addEventListener('mouseout', function (event) { if (event.clientY <= 0 && !event.relatedTarget) { open(); } }); document.addEventListener('keydown', function (event) { if (!isOpen) { return; } if (event.key === 'Escape') { close(); return; } if (event.key !== 'Tab') { return; } var nodes = focusable(); if (!nodes.length) { return; } var first = nodes[0]; var last = nodes[nodes.length - 1]; if (event.shiftKey && document.activeElement === first) { event.preventDefault(); last.focus(); } else if (!event.shiftKey && document.activeElement === last) { event.preventDefault(); first.focus(); } }); if (closeButton) { closeButton.addEventListener('click', close); } if (backdrop) { backdrop.addEventListener('click', close); } if (copyButton) { copyButton.addEventListener('click', function () { var code = popup.querySelector('[data-fivemx-exit-popup-code]'); if (!code || !navigator.clipboard) { return; } navigator.clipboard.writeText(code.textContent.trim()).then(function () { copyButton.textContent = copyButton.getAttribute('data-copied-label') || copyButton.textContent; }).catch(function () {}); }); } }()); </script> <script id="fivemx-elementor-frontend-config-fallback">window.elementorFrontendConfig=window.elementorFrontendConfig||{"environmentMode":{"edit":false,"wpPreview":false,"isScriptDebug":false},"i18n":{"shareOnFacebook":"Partager sur Facebook","shareOnX":"Share on X","pinIt":"L’épingler","download":"Télécharger","downloadImage":"Télécharger une image","fullscreen":"Plein écran","zoom":"Zoom","share":"Partager","playVideo":"Lire la vidéo","previous":"Précédent","next":"Suivant","close":"Fermer","a11yCarouselPrevSlideMessage":"Diapositive précédente","a11yCarouselNextSlideMessage":"Diapositive suivante","a11yCarouselFirstSlideMessage":"Ceci est la première diapositive","a11yCarouselLastSlideMessage":"Ceci est la dernière diapositive","a11yCarouselPaginationBulletMessage":"Aller à la diapositive"},"is_rtl":false,"breakpoints":{"xs":0,"sm":480,"md":768,"lg":1025,"xl":1440,"xxl":1600},"responsive":{"breakpoints":{"mobile":{"label":"Portrait mobile","value":767,"default_value":767,"direction":"max","is_enabled":true},"mobile_extra":{"label":"Mobile Paysage","value":880,"default_value":880,"direction":"max","is_enabled":false},"tablet":{"label":"Tablette en mode portrait","value":1024,"default_value":1024,"direction":"max","is_enabled":true},"tablet_extra":{"label":"Tablette en mode paysage","value":1200,"default_value":1200,"direction":"max","is_enabled":false},"laptop":{"label":"Portable","value":1366,"default_value":1366,"direction":"max","is_enabled":false},"widescreen":{"label":"Écran large","value":2400,"default_value":2400,"direction":"min","is_enabled":false}},"hasCustomBreakpoints":false},"version":"4.2.1","is_static":false,"experimentalFeatures":{"e_font_icon_svg":true,"additional_custom_breakpoints":true,"container":true,"e_optimized_markup":true,"e_panel_promotions":true,"e_pro_free_trial_popup":true,"nested-elements":true,"e_atomic_elements":true,"atomic_widgets_should_enforce_capabilities":true,"editor_mcp":true,"e_bc_migrations":true,"e_classes":true,"global_classes_should_enforce_capabilities":true,"e_variables":true,"e_variables_manager":true,"e_opt_in_v4_page":true,"e_opt_in_v4":true,"e_components":true,"e_interactions":true,"e_widget_creation":true,"import-export-customization":true},"urls":{"assets":"https://fivemx.com/wp-content/plugins/elementor/assets/","ajaxurl":"https://fivemx.com/wp-admin/admin-ajax.php","uploadUrl":"https://fivemx.com/wp-content/uploads"},"nonces":{"floatingButtonsClickTracking":"b62784dc79","atomicFormsSendForm":"f316b68f81"},"swiperClass":"swiper","settings":{"page":[],"editorPreferences":[]},"kit":{"active_breakpoints":["viewport_mobile","viewport_tablet"],"global_image_lightbox":"yes","lightbox_enable_counter":"yes","lightbox_enable_fullscreen":"yes","lightbox_enable_zoom":"yes","lightbox_enable_share":"yes","lightbox_title_src":"title","lightbox_description_src":"description"},"post":{"id":184927,"title":"How%20To%20Create%20a%20Custom%20FiveM%20Loading%20Screen","excerpt":"","featuredImage":"https://cdn.fivemx.com/wp-content/uploads/2025/04/fivem-loading-screen.webp"}};</script> <style id="woocommerce-product-collection-style-inline-css"> @keyframes wc-skeleton-shimmer{to{transform:translateX(100%)}}.wp-block-woocommerce-product-collection{margin-bottom:30px}.wp-block-woocommerce-product-collection .wc-block-components-product-stock-indicator{text-align:center}.wp-block-woocommerce-product-collection h2.wp-block-heading{font-size:var(--wp--preset--font-size--small,14px);line-height:1.4}.wp-block-woocommerce-product-collection .wc-block-components-notices:not(:has(*))+.wc-block-product-template{margin-block-start:0}@media(max-width:600px)and (hover:none)and (pointer:coarse){.wp-block-woocommerce-product-collection:has(.is-product-collection-layout-carousel) :where(.wc-block-next-previous-buttons.wc-block-next-previous-buttons){display:none}}.wc-block-components-notice-banner .wc-block-components-button.wc-block-components-notice-banner__dismiss[hidden]{display:none} /*# sourceURL=https://fivemx.com/wp-content/plugins/woocommerce/assets/client/blocks/woocommerce/product-collection-style.css */ </style> <style id="wp-interactivity-router-animations-inline-css"> .wp-interactivity-router-loading-bar { position: fixed; top: 0; left: 0; margin: 0; padding: 0; width: 100vw; max-width: 100vw !important; height: 4px; background-color: #000; opacity: 0 } .wp-interactivity-router-loading-bar.start-animation { animation: wp-interactivity-router-loading-bar-start-animation 30s cubic-bezier(0.03, 0.5, 0, 1) forwards } .wp-interactivity-router-loading-bar.finish-animation { animation: wp-interactivity-router-loading-bar-finish-animation 300ms ease-in } @keyframes wp-interactivity-router-loading-bar-start-animation { 0% { transform: scaleX(0); transform-origin: 0 0; opacity: 1 } 100% { transform: scaleX(1); transform-origin: 0 0; opacity: 1 } } @keyframes wp-interactivity-router-loading-bar-finish-animation { 0% { opacity: 1 } 50% { opacity: 1 } 100% { opacity: 0 } } /*# sourceURL=wp-interactivity-router-animations-inline-css */ </style> <style id="core-block-supports-inline-css"> .wp-container-core-group-is-layout-3c957fdc{flex-direction:column;align-items:center;} /*# sourceURL=core-block-supports-inline-css */ </style> <script id="trp-dynamic-translator-js-extra"> var trp_data = {"trp_custom_ajax_url":"https://fivemx.com/wp-content/plugins/translatepress-multilingual/includes/trp-ajax.php","trp_wp_ajax_url":"https://fivemx.com/wp-admin/admin-ajax.php","trp_language_to_query":"fr_FR","trp_original_language":"en_US","trp_current_language":"fr_FR","trp_skip_selectors":["[data-no-translation]","[data-no-dynamic-translation]","[data-trp-translate-id-innertext]","script","style","head","trp-span","translate-press","#billing_country","#shipping_country","#billing_state","#shipping_state","#select2-billing_country-results","#select2-billing_state-results","#select2-shipping_country-results","#select2-shipping_state-results",".woocommerce-loop-product__title","[data-trp-translate-id]","[data-trpgettextoriginal]","[data-trp-post-slug]"],"trp_base_selectors":["data-trp-translate-id","data-trpgettextoriginal","data-trp-post-slug"],"trp_attributes_selectors":{"text":{"accessor":"outertext","attribute":false},"block":{"accessor":"innertext","attribute":false},"image_src":{"selector":"img[src]","accessor":"src","attribute":true},"submit":{"selector":"input[type='submit'],input[type='button'], input[type='reset']","accessor":"value","attribute":true},"placeholder":{"selector":"input[placeholder],textarea[placeholder]","accessor":"placeholder","attribute":true},"title":{"selector":"[title]","accessor":"title","attribute":true},"a_href":{"selector":"a[href]","accessor":"href","attribute":true},"button":{"accessor":"outertext","attribute":false},"option":{"accessor":"innertext","attribute":false},"aria_label":{"selector":"[aria-label]","accessor":"aria-label","attribute":true},"video_src":{"selector":"video[src]","accessor":"src","attribute":true},"video_poster":{"selector":"video[poster]","accessor":"poster","attribute":true},"video_source_src":{"selector":"video source[src]","accessor":"src","attribute":true},"audio_src":{"selector":"audio[src]","accessor":"src","attribute":true},"audio_source_src":{"selector":"audio source[src]","accessor":"src","attribute":true},"picture_image_src":{"selector":"picture image[src]","accessor":"src","attribute":true},"picture_source_srcset":{"selector":"picture source[srcset]","accessor":"srcset","attribute":true},"image_alt":{"selector":"img[alt]","accessor":"alt","attribute":true},"meta_desc":{"selector":"meta[name=\"description\"],meta[property=\"og:title\"],meta[property=\"og:description\"],meta[property=\"og:site_name\"],meta[property=\"og:image:alt\"],meta[name=\"twitter:title\"],meta[name=\"twitter:description\"],meta[name=\"twitter:image:alt\"],meta[name=\"DC.Title\"],meta[name=\"DC.Description\"],meta[property=\"article:section\"],meta[property=\"article:tag\"]","accessor":"content","attribute":true},"page_title":{"selector":"title","accessor":"innertext","attribute":false},"meta_desc_img":{"selector":"meta[property=\"og:image\"],meta[property=\"og:image:secure_url\"],meta[name=\"twitter:image\"]","accessor":"content","attribute":true}},"trp_attributes_accessors":["outertext","innertext","src","value","placeholder","title","href","aria-label","poster","srcset","alt","content"],"gettranslationsnonceregular":"aa26fb909f","showdynamiccontentbeforetranslation":"","skip_strings_from_dynamic_translation":[],"skip_strings_from_dynamic_translation_for_substrings":{"href":["amazon-adsystem","googleads","g.doubleclick"]},"duplicate_detections_allowed":"100","trp_translate_numerals_opt":"no","trp_no_auto_translation_selectors":["[data-no-auto-translation]"]}; //# sourceURL=trp-dynamic-translator-js-extra </script> <script id="trp-dynamic-translator-js-before"> (function () { 'use strict'; var userAgent = String((window.navigator && window.navigator.userAgent) || ''); var isCrawler = new RegExp("ahrefs|bingbot|bot|crawler|dataforseo|dotbot|facebookexternalhit|gptbot|meta-externalagent|oai-searchbot|semrush|slurp|spider|yandex", 'i').test(userAgent); window.__fivemxCrawlerRuntime = isCrawler; if (isCrawler && typeof window.trp_data === 'object') { window.trp_data.trp_language_to_query = ''; } }()); //# sourceURL=trp-dynamic-translator-js-before </script> <script id="trp-dynamic-translator-js" defer src="https://fivemx.com/wp-content/plugins/translatepress-multilingual/assets/js/trp-translate-dom-changes.js?ver=3.3.1"></script> <script id="cgkit-js-cookie-js" defer src="https://fivemx.com/wp-content/plugins/commercegurus-commercekit/assets/js/js.cookie.min.js?ver=3.0.5"></script> <script id="commercekit-wishlist-js" defer src="https://fivemx.com/wp-content/plugins/commercegurus-commercekit/assets/js/wishlist.js?ver=2.5.2"></script> <script id="commercekit-ajax-search-js" defer src="https://fivemx.com/wp-content/plugins/commercegurus-commercekit/assets/js/ajax-search.js?ver=2.5.2"></script> <script id="shoptimizer-main-js" src="https://fivemx.com/wp-content/themes/shoptimizer/assets/js/main.min.js?ver=2.9.5"></script> <script id="shoptimizer-main-js-after"> document.querySelectorAll('.woocommerce-image__wrapper').forEach(carousel => { const carouselInner = carousel.querySelector('.shoptimizer-plp-image-wrapper'); const dots = carousel.querySelectorAll('.shoptimizer-plp-carousel--dot'); const carouselContainer = carousel.querySelector('.shoptimizer-plp-carousel-container'); // Check if the carousel container exists if (carouselContainer) { function updateDots() { const scrollLeft = carouselContainer.scrollLeft; const viewportWidth = carouselContainer.clientWidth; const index = Math.round(scrollLeft / viewportWidth); dots.forEach((dot, i) => { dot.classList.toggle('active', i === index); }); } let isScrolling; carouselContainer.addEventListener('scroll', () => { clearTimeout(isScrolling); isScrolling = setTimeout(() => { updateDots(); }, 50); }); // Initialize the dots updateDots(); } else { console.warn('Carousel container not found:', carousel); } }); jQuery( document ).ready( function( $ ) { $( 'body' ).on( 'added_to_cart', function( event, fragments, cart_hash ) { if ( ! $( 'body' ).hasClass( 'elementor-editor-active' ) ) { $( 'body' ).addClass( 'drawer-open' ); $( '#shoptimizerCartDrawer').focus(); } } ); } ); document.addEventListener( 'DOMContentLoaded', function() { document.addEventListener( 'click', function( event ) { var is_inner = event.target.closest( '.shoptimizer-mini-cart-wrap' ); if ( ! event.target.classList.contains( 'shoptimizer-mini-cart-wrap' ) && ! is_inner ) { document.querySelector( 'body' ).classList.remove( 'drawer-open' ); } var is_inner2 = event.target.closest( '.shoptimizer-cart' ); if ( event.target.classList.contains( 'shoptimizer-cart' ) || is_inner2 ) { var is_header = event.target.closest( '.site-header-cart' ); var is_shortcode = event.target.closest( '.shoptimizer-cart-shortcode' ); if ( is_header || is_shortcode ) { event.preventDefault(); document.querySelector( 'body' ).classList.toggle( 'drawer-open' ); document.getElementById('shoptimizerCartDrawer').focus(); } } if ( event.target.classList.contains( 'close-drawer' ) ) { document.querySelector( 'body' ).classList.remove( 'drawer-open' ); } } ); } ); // Mini Cart Ajax state. document.addEventListener( 'DOMContentLoaded', function() { document.querySelector( '#ajax-loading' ).style.display = 'none'; } ); ; ( function( $ ) { 'use strict'; var events_to_monitor = [ 'wc-ajax=get_refreshed_fragments', 'wc-ajax=remove_from_cart', ]; function handle_mini_cart_ajax_events( settings, show_loading ) { if ( events_to_monitor.some( function( event ) { return settings.url.indexOf( event ) !== -1; })) { if ( show_loading ) { $( '#ajax-loading' ).css( 'display', 'block' ); } else { $( '#ajax-loading' ).css( 'display', 'none' ); } } } events_to_monitor.forEach( function( event ) { $( document ).ajaxSend( function( event, jqXHR, settings ) { handle_mini_cart_ajax_events( settings, true ); }); $( document ).ajaxComplete( function( event, jqXHR, settings ) { handle_mini_cart_ajax_events( settings, false ); }); }); // Close anon function. }( jQuery ) ); var observer = new IntersectionObserver(function(entries) { if(entries[0].intersectionRatio === 0) document.querySelector('.col-full-nav').classList.add('is_stuck'); else if(entries[0].intersectionRatio === 1) document.querySelector('.col-full-nav').classList.remove('is_stuck'); }, { threshold: [0,1] }); var s_observer_elm = document.querySelector('.s-observer'); if ( s_observer_elm ) { observer.observe(s_observer_elm); } //# sourceURL=shoptimizer-main-js-after </script> <script async data-wp-strategy="async" fetchpriority="low" id="comment-reply-js" src="https://fivemx.com/wp-includes/js/comment-reply.min.js?ver=7.0.2"></script> <script id="sourcebuster-js-js" defer src="https://fivemx.com/wp-content/plugins/woocommerce/assets/js/sourcebuster/sourcebuster.min.js?ver=11.0.0"></script> <script id="wc-order-attribution-js-extra"> var wc_order_attribution = {"params":{"lifetime":0.9856262833675564,"session":30,"base64":false,"ajaxurl":"https://fivemx.com/wp-admin/admin-ajax.php","prefix":"wc_order_attribution_","allowTracking":true},"fields":{"source_type":"current.typ","referrer":"current_add.rf","utm_campaign":"current.cmp","utm_source":"current.src","utm_medium":"current.mdm","utm_content":"current.cnt","utm_id":"current.id","utm_term":"current.trm","utm_source_platform":"current.plt","utm_creative_format":"current.fmt","utm_marketing_tactic":"current.tct","session_entry":"current_add.ep","session_start_time":"current_add.fd","session_pages":"session.pgs","session_count":"udata.vst","user_agent":"udata.uag"}}; //# sourceURL=wc-order-attribution-js-extra </script> <script id="wc-order-attribution-js" defer src="https://fivemx.com/wp-content/plugins/woocommerce/assets/js/frontend/order-attribution.min.js?ver=11.0.0"></script> <script id="yay-currency-callback-general-js-extra"> var yay_callback_data = {"admin_url":"https://fivemx.com/wp-admin/admin.php?page=wc-settings","ajaxurl":"https://fivemx.com/wp-admin/admin-ajax.php","nonce":"abe58d2adb","isShowOnMenu":"0","isPolylangCompatible":"0","isDisplayFlagInSwitcher":"1","yayCurrencyPluginURL":"https://fivemx.com/wp-content/plugins/yaycurrency-pro/","converted_currency":[{"ID":174768,"currency":"USD","currencyPosition":"left","currencyCodePosition":"not_display","thousandSeparator":",","decimalSeparator":".","numberDecimal":"2","roundingType":"disabled","roundingValue":"1","subtractAmount":"0","rate":"1","fee":{"type":"fixed","value":"0"},"status":"1","paymentMethods":["all"],"countries":["default"],"symbol":"$"},{"ID":174769,"currency":"EUR","currencyPosition":"left","currencyCodePosition":"not_display","thousandSeparator":",","decimalSeparator":".","numberDecimal":"2","roundingType":"disabled","roundingValue":"1","subtractAmount":"0","rate":"0.8671","fee":{"type":"fixed","value":"0"},"status":"1","paymentMethods":["all"],"countries":["default"],"symbol":"€"},{"ID":174770,"currency":"GBP","currencyPosition":"left","currencyCodePosition":"not_display","thousandSeparator":",","decimalSeparator":".","numberDecimal":"2","roundingType":"disabled","roundingValue":"1","subtractAmount":"0","rate":"0.7439","fee":{"type":"fixed","value":"0"},"status":"1","paymentMethods":["all"],"countries":["default"],"symbol":"£"}],"checkout_diff_currency":"1","fallback_currency_code":"USD","default_currency_code":"USD","currency_symbol_position":"left","formatted_price_woo_blocks":"yes","fixed_product_price_enable":"0","show_approximate_price":"yes","cart_page":"","cookie_lifetime_days":"30","hide_dropdown_switcher":"","cookie_name":"yay_currency_widget","cookie_switcher_name":"yay_currency_do_change_switcher","cache_compatible":"1","current_theme":"shoptimizer","flag_fallbacks":{"default":"https://fivemx.com/wp-content/plugins/yaycurrency-pro/assets/flags/default.svg"},"apply_currency_before_cache":{"ID":174768,"rateFee":1},"minicart_contents_class":"a.cart-contents"}; //# sourceURL=yay-currency-callback-general-js-extra </script> <script id="yay-currency-callback-general-js" src="https://fivemx.com/wp-content/plugins/yaycurrency-pro/src/helpers/general.helper.min.js?ver=3.3.4"></script> <script id="yay-currency-callback-general-js-after"> (function () { function patchYayCurrencyHelper() { if (!window.YayCurrency_Callback || !window.YayCurrency_Callback.Helper) { return false; } var helper = window.YayCurrency_Callback.Helper; if (typeof helper.getRateFeeByCurrency === 'function' && !helper.getRateFeeByCurrency.__fivemxGuarded) { var getRateFeeByCurrency = helper.getRateFeeByCurrency; helper.getRateFeeByCurrency = function (currentCurrency) { try { return getRateFeeByCurrency.apply(this, arguments); } catch (error) { var fallbackCurrency = currentCurrency || (typeof helper.getCurrentCurrency === 'function' ? helper.getCurrentCurrency() : null); var fallbackRate = fallbackCurrency && Number.parseFloat(fallbackCurrency.rate); return Number.isFinite(fallbackRate) ? fallbackRate : 1; } }; helper.getRateFeeByCurrency.__fivemxGuarded = true; } if (typeof helper.handleFilterByPriceClassicEditor === 'function' && !helper.handleFilterByPriceClassicEditor.__fivemxGuarded) { var handleFilterByPriceClassicEditor = helper.handleFilterByPriceClassicEditor; helper.handleFilterByPriceClassicEditor = function (currencyID) { var applyCurrency = typeof helper.getCurrentCurrency === 'function' ? helper.getCurrentCurrency(currencyID) : null; if (!applyCurrency || !applyCurrency.currency || !applyCurrency.fee) { return; } return handleFilterByPriceClassicEditor.apply(this, arguments); }; helper.handleFilterByPriceClassicEditor.__fivemxGuarded = true; } return true; } if (!patchYayCurrencyHelper()) { document.addEventListener('DOMContentLoaded', patchYayCurrencyHelper, { once: true }); } }()); //# sourceURL=yay-currency-callback-general-js-after </script> <script id="yay-currency-callback-blocks-js-extra"> var yay_callback_data = {"admin_url":"https://fivemx.com/wp-admin/admin.php?page=wc-settings","ajaxurl":"https://fivemx.com/wp-admin/admin-ajax.php","nonce":"abe58d2adb","isShowOnMenu":"0","isPolylangCompatible":"0","isDisplayFlagInSwitcher":"1","yayCurrencyPluginURL":"https://fivemx.com/wp-content/plugins/yaycurrency-pro/","converted_currency":[{"ID":174768,"currency":"USD","currencyPosition":"left","currencyCodePosition":"not_display","thousandSeparator":",","decimalSeparator":".","numberDecimal":"2","roundingType":"disabled","roundingValue":"1","subtractAmount":"0","rate":"1","fee":{"type":"fixed","value":"0"},"status":"1","paymentMethods":["all"],"countries":["default"],"symbol":"$"},{"ID":174769,"currency":"EUR","currencyPosition":"left","currencyCodePosition":"not_display","thousandSeparator":",","decimalSeparator":".","numberDecimal":"2","roundingType":"disabled","roundingValue":"1","subtractAmount":"0","rate":"0.8671","fee":{"type":"fixed","value":"0"},"status":"1","paymentMethods":["all"],"countries":["default"],"symbol":"€"},{"ID":174770,"currency":"GBP","currencyPosition":"left","currencyCodePosition":"not_display","thousandSeparator":",","decimalSeparator":".","numberDecimal":"2","roundingType":"disabled","roundingValue":"1","subtractAmount":"0","rate":"0.7439","fee":{"type":"fixed","value":"0"},"status":"1","paymentMethods":["all"],"countries":["default"],"symbol":"£"}],"checkout_diff_currency":"1","fallback_currency_code":"USD","default_currency_code":"USD","currency_symbol_position":"left","formatted_price_woo_blocks":"yes","fixed_product_price_enable":"0","show_approximate_price":"yes","cart_page":"","cookie_lifetime_days":"30","hide_dropdown_switcher":"","cookie_name":"yay_currency_widget","cookie_switcher_name":"yay_currency_do_change_switcher","cache_compatible":"1","current_theme":"shoptimizer","flag_fallbacks":{"default":"https://fivemx.com/wp-content/plugins/yaycurrency-pro/assets/flags/default.svg"},"apply_currency_before_cache":{"ID":174768,"rateFee":1},"minicart_contents_class":"a.cart-contents"}; //# sourceURL=yay-currency-callback-blocks-js-extra </script> <script id="yay-currency-callback-blocks-js" defer src="https://fivemx.com/wp-content/plugins/yaycurrency-pro/src/helpers/blocks.helper.min.js?ver=3.3.4"></script> <script id="yay-currency-frontend-script-js-extra"> var yayCurrency = {"admin_url":"https://fivemx.com/wp-admin/admin.php?page=wc-settings","ajaxurl":"https://fivemx.com/wp-admin/admin-ajax.php","nonce":"abe58d2adb","isShowOnMenu":"0","isPolylangCompatible":"0","isDisplayFlagInSwitcher":"1","yayCurrencyPluginURL":"https://fivemx.com/wp-content/plugins/yaycurrency-pro/","converted_currency":[{"ID":174768,"currency":"USD","currencyPosition":"left","currencyCodePosition":"not_display","thousandSeparator":",","decimalSeparator":".","numberDecimal":"2","roundingType":"disabled","roundingValue":"1","subtractAmount":"0","rate":"1","fee":{"type":"fixed","value":"0"},"status":"1","paymentMethods":["all"],"countries":["default"],"symbol":"$"},{"ID":174769,"currency":"EUR","currencyPosition":"left","currencyCodePosition":"not_display","thousandSeparator":",","decimalSeparator":".","numberDecimal":"2","roundingType":"disabled","roundingValue":"1","subtractAmount":"0","rate":"0.8671","fee":{"type":"fixed","value":"0"},"status":"1","paymentMethods":["all"],"countries":["default"],"symbol":"€"},{"ID":174770,"currency":"GBP","currencyPosition":"left","currencyCodePosition":"not_display","thousandSeparator":",","decimalSeparator":".","numberDecimal":"2","roundingType":"disabled","roundingValue":"1","subtractAmount":"0","rate":"0.7439","fee":{"type":"fixed","value":"0"},"status":"1","paymentMethods":["all"],"countries":["default"],"symbol":"£"}],"checkout_diff_currency":"1","fallback_currency_code":"USD","default_currency_code":"USD","currency_symbol_position":"left","formatted_price_woo_blocks":"yes","fixed_product_price_enable":"0","show_approximate_price":"yes","cart_page":"","cookie_lifetime_days":"30","hide_dropdown_switcher":"","cookie_name":"yay_currency_widget","cookie_switcher_name":"yay_currency_do_change_switcher","cache_compatible":"1","current_theme":"shoptimizer","flag_fallbacks":{"default":"https://fivemx.com/wp-content/plugins/yaycurrency-pro/assets/flags/default.svg"},"apply_currency_before_cache":{"ID":174768,"rateFee":1}}; //# sourceURL=yay-currency-frontend-script-js-extra </script> <script id="yay-currency-frontend-script-js" defer src="https://fivemx.com/wp-content/plugins/yaycurrency-pro/src/script.min.js?ver=3.3.4"></script> <script id="yay-currency-third-party-js" defer src="https://fivemx.com/wp-content/plugins/yaycurrency-pro/src/compatibles/third-party.min.js?ver=3.3.4"></script> <script id="yay-currency-caching-script-js-extra"> var yay_currency_caching_data = {"ajax_url":"https://fivemx.com/wp-admin/admin-ajax.php","nonce":"b0007bbc44","rest_url":"https://fivemx.com/fr/wp-json/yaycurrency/v1/caching","rest_nonce":"595b6dc136","should_refresh_fragment":"yes","yay_currency_current_url":"https://fivemx.com/fr/how-to-create-a-custom-fivem-loading-screen"}; //# sourceURL=yay-currency-caching-script-js-extra </script> <script id="yay-currency-caching-script-js-before"> (function () { 'use strict'; var userAgent = String((window.navigator && window.navigator.userAgent) || ''); var isCrawler = new RegExp("ahrefs|bingbot|bot|crawler|dataforseo|dotbot|facebookexternalhit|gptbot|meta-externalagent|oai-searchbot|semrush|slurp|spider|yandex", 'i').test(userAgent); window.__fivemxCrawlerRuntime = isCrawler; if (isCrawler && typeof window.trp_data === 'object') { window.trp_data.trp_language_to_query = ''; } }()); (function ($, refreshUrl) { 'use strict'; if ( window.__fivemxCrawlerRuntime === true || !$ || typeof $.ajax !== 'function' || typeof window.yay_currency_caching_data !== 'object' || !refreshUrl ) { return; } var data = window.yay_currency_caching_data; var restUrl = String(data.rest_url || '').replace(/\/$/, ''); if (!restUrl || window.__fivemxYayCurrencyNonceGuard) { return; } window.__fivemxYayCurrencyNonceGuard = true; var originalAjax = $.ajax; var refreshRequest = null; var targetUrls = [ restUrl + '/get_price_html', restUrl + '/currency_switcher_html' ]; function restoreAjax() { if ($.ajax === guardedAjax) { $.ajax = originalAjax; } } function refreshNonce() { if (refreshRequest) { return refreshRequest; } refreshRequest = originalAjax.call($, { url: refreshUrl, method: 'GET', dataType: 'json', cache: false, headers: { 'X-Yay-Nonce-Request': '1', 'Cache-Control': 'no-cache' }, xhrFields: { withCredentials: true } }); return refreshRequest; } function guardedAjax(url, settings) { var options = typeof url === 'object' && url !== null ? url : settings; var targetUrl = options && typeof options.url === 'string' ? options.url : ''; var method = String((options && (options.type || options.method)) || 'GET').toUpperCase(); if (!options || method !== 'POST' || !targetUrls.includes(targetUrl) || options.__fivemxNonceReady) { return originalAjax.apply(this, arguments); } var context = this; var deferred = $.Deferred(); var activeRequest = null; var promise = deferred.promise(); refreshNonce() .done(function (response) { if (!response || !response.nonce) { deferred.rejectWith(this, arguments); restoreAjax(); return; } data.rest_nonce = response.nonce; var requestOptions = $.extend({}, options, { headers: $.extend({}, options.headers || {}, { 'X-WP-Nonce': response.nonce }), __fivemxNonceReady: true }); activeRequest = originalAjax.call(context, requestOptions); activeRequest .done(function () { deferred.resolveWith(this, arguments); }) .fail(function () { deferred.rejectWith(this, arguments); }); restoreAjax(); }) .fail(function () { deferred.rejectWith(this, arguments); restoreAjax(); }); promise.abort = function (statusText) { if (activeRequest && typeof activeRequest.abort === 'function') { activeRequest.abort(statusText); } else { deferred.rejectWith(context, [null, statusText || 'abort']); } return promise; }; return promise; } $.ajax = guardedAjax; }(window.jQuery, "https:\/\/fivemx.com\/wp-admin\/admin-ajax.php?action=fivemx_yaycurrency_rest_nonce")); //# sourceURL=yay-currency-caching-script-js-before </script> <script id="yay-currency-caching-script-js" src="https://fivemx.com/wp-content/plugins/yaycurrency-pro/src/compatibles/cache/yay-caching.min.js?ver=3.3.4"></script> <script id="enlighterjs-js" src="https://fivemx.com/wp-content/plugins/enlighter/cache/enlighterjs.min.js?ver=eQazT5C2%2FIg515i"></script> <script id="enlighterjs-js-after"> !function(e,n){if("undefined"!=typeof EnlighterJS){var o={"selectors":{"block":"pre.EnlighterJSRAW","inline":"code.EnlighterJSRAW"},"options":{"indent":4,"ampersandCleanup":true,"linehover":true,"rawcodeDbclick":false,"textOverflow":"break","linenumbers":true,"theme":"atomic","language":"generic","retainCssClasses":false,"collapse":false,"toolbarOuter":"","toolbarTop":"{BTN_RAW}{BTN_COPY}{BTN_WINDOW}{BTN_WEBSITE}","toolbarBottom":""}};(e.EnlighterJSINIT=function(){EnlighterJS.init(o.selectors.block,o.selectors.inline,o.options)})()}else{(n&&(n.error||n.log)||function(){})("Error: EnlighterJS resources not loaded yet!")}}(window,console); //# sourceURL=enlighterjs-js-after </script> <div class="fivemx-language-switcher" role="navigation" aria-label="Langue" data-no-translation-aria-label=""><div class="trp-shortcode-switcher__wrapper" style="--bg:#ffffff;--bg-hover:#0000000d;--text:#143852;--text-hover:#1d2327;--border:1px solid #1438521a;--border-width:1px;--border-color:#1438521a;--border-radius:5px;--flag-radius:2px;--flag-size:18px;--aspect-ratio:4/3;--font-size:14px;--transition-duration:0.2s" role="group" data-open-mode="click"> <!-- ANCHOR (in-flow only; sizing/borders; inert) --> <div class="trp-language-switcher trp-ls-dropdown trp-shortcode-switcher trp-shortcode-anchor trp-open-on-click" aria-hidden="true" inert data-no-translation> <div class="trp-current-language-item__wrapper"> <a class="trp-language-item trp-language-item__default trp-language-item__current" data-no-translation href="https://fivemx.com/fr/comment-creer-un-ecran-de-chargement-fivem-personnalise/" title="Français"><img src="https://fivemx.com/wp-content/plugins/translatepress-multilingual/assets/flags/4x3/fr_FR.svg" class="trp-flag-image" alt="French" role="presentation" loading="lazy" aria-hidden="true" /><span class="trp-language-item-name">Français</span></a> <svg class="trp-shortcode-arrow" width="20" height="20" viewbox="0 0 20 21" fill="none" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"> <path d="M5 8L10 13L15 8" stroke="var(--text)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> </div> <!-- OVERLAY (positioned; interactive surface) --> <div class="trp-language-switcher trp-ls-dropdown trp-shortcode-switcher trp-shortcode-overlay trp-open-on-click" role="navigation" aria-label="Sélecteur de langue du site web" data-no-translation > <div class="trp-current-language-item__wrapper"> <div class="trp-language-item trp-language-item__default trp-language-item__current" data-no-translation role="button" aria-expanded="false" tabindex="0" aria-label="Changer de langue : Français" aria-controls="trp-shortcode-dropdown-6a75afe27f909" data-no-translation-aria-label=""><img src="https://fivemx.com/wp-content/plugins/translatepress-multilingual/assets/flags/4x3/fr_FR.svg" class="trp-flag-image" alt="French" role="presentation" loading="lazy" aria-hidden="true" /><span class="trp-language-item-name">Français</span></div> <svg class="trp-shortcode-arrow" width="20" height="20" viewbox="0 0 20 21" fill="none" aria-hidden="true" focusable="false" xmlns="http://www.w3.org/2000/svg"> <path d="M5 8L10 13L15 8" stroke="var(--text)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/> </svg> </div> <div class="trp-switcher-dropdown-list" id="trp-shortcode-dropdown-6a75afe27f909" role="group" aria-label="Langues disponibles" hidden inert > <a class="trp-language-item" href="https://fivemx.com/how-to-create-a-custom-fivem-loading-screen/" title="Anglais"> <img src="https://fivemx.com/wp-content/plugins/translatepress-multilingual/assets/flags/4x3/en_US.svg" class="trp-flag-image" alt="Anglais" role="presentation" loading="lazy" aria-hidden="true" /> <span class="trp-language-item-name" data-no-translation>English</span> </a> <a class="trp-language-item" href="https://fivemx.com/de/so-erstellen-sie-einen-benutzerdefinierten-fivem-ladebildschirm/" title="Allemand"> <img src="https://fivemx.com/wp-content/plugins/translatepress-multilingual/assets/flags/4x3/de_DE.svg" class="trp-flag-image" alt="Allemand" role="presentation" loading="lazy" aria-hidden="true" /> <span class="trp-language-item-name" data-no-translation>Deutsch</span> </a> <a class="trp-language-item" href="https://fivemx.com/pt/como-criar-uma-tela-de-carregamento-fivem-personalizada/" title="Português do Brasil"> <img src="https://fivemx.com/wp-content/plugins/translatepress-multilingual/assets/flags/4x3/pt_BR.svg" class="trp-flag-image" alt="portugais" role="presentation" loading="lazy" aria-hidden="true" /> <span class="trp-language-item-name" data-no-translation>Português do Brasil</span> </a> <a class="trp-language-item" href="https://fivemx.com/es/como-crear-una-pantalla-de-carga-fivem-personalizada/" title="Espagnol"> <img src="https://fivemx.com/wp-content/plugins/translatepress-multilingual/assets/flags/4x3/es_ES.svg" class="trp-flag-image" alt="Espagnol" role="presentation" loading="lazy" aria-hidden="true" /> <span class="trp-language-item-name" data-no-translation>Español</span> </a> </div> </div> </div> </div><div style="position:absolute;margin:-1px;padding:0;height:1px;width:1px;overflow:hidden;clip-path:inset(50%);border:0;word-wrap:normal !important;"><p id="a11y-speak-intro-text" class="a11y-speak-intro-text" hidden data-no-translation="" data-trp-gettext="">Notifications</p><div id="a11y-speak-assertive" class="a11y-speak-region" aria-live="assertive" aria-relevant="additions text" aria-atomic="true"></div><div id="a11y-speak-polite" class="a11y-speak-region" aria-live="polite" aria-relevant="additions text" aria-atomic="true"></div></div> <script id="fivemx-plausible-woocommerce-events"> (function(config) { if (!window.plausible || window.fivemxPlausibleWooLoaded) return; window.fivemxPlausibleWooLoaded = true; function track(eventName, props, revenue) { var name = config.analytics_events && config.analytics_events[eventName]; if (!name) return; var options = {}; if (props) options.props = props; if (revenue) { options.revenue = revenue; } try { window.plausible(name, options); } catch (error) { // Storefront behavior must not depend on analytics transport availability. } try { window.dispatchEvent(new CustomEvent('fivemx:analytics', { detail: { event: eventName, props: props || {} } })); } catch (error) { // Qualitative replay filtering is optional and must never block Plausible. } } // Storefront modules can request canonical events only after this consent-gated runtime exists. window.fivemxAnalytics = Object.freeze({ track: function(eventName, props) { track(eventName, props); } }); function rememberOnce(key) { try { if (sessionStorage.getItem(key)) return false; sessionStorage.setItem(key, '1'); } catch (error) { // Continue without storage-based deduping when the browser blocks it. } try { if (localStorage.getItem(key)) return false; localStorage.setItem(key, '1'); } catch (error) { return true; } return true; } function rememberSessionOnce(key) { try { if (sessionStorage.getItem(key)) return false; sessionStorage.setItem(key, '1'); } catch (error) { return rememberRecently(key, 3000); } return true; } var recentEvents = {}; function rememberRecently(key, ttl) { var now = Date.now(); if (recentEvents[key] && now - recentEvents[key] < ttl) return false; recentEvents[key] = now; return true; } function cleanProperty(value, fallback) { value = String(value || fallback || '').trim().replace(/\s+/g, ' '); return value.slice(0, 120); } function canonicalPath(value) { value = cleanProperty(value, '/'); if (value.charAt(0) !== '/') value = '/' + value; if (value.length > 1 && value.indexOf('?') === -1 && value.charAt(value.length - 1) !== '/') value += '/'; return value; } function rememberJourneyContext(value) { value = cleanProperty(value, ''); if (!value) return; try { sessionStorage.setItem('fivemx_buyer_context', value); } catch (error) { // Tracking still works without session context persistence. } document.cookie = 'fivemx_buyer_context=' + encodeURIComponent(value) + '; Path=/; Max-Age=604800; SameSite=Lax' + (location.protocol === 'https:' ? '; Secure' : ''); } function journeyContext() { var context = cleanProperty(config.buyer_context || '', ''); if (context) return context; try { return cleanProperty(sessionStorage.getItem('fivemx_buyer_context') || '', ''); } catch (error) { return ''; } } // Attribution used to have exactly one input: a click on a link that // carried both `data-fivemx-shop-bridge` and an explicit // `data-fivemx-recommendation-context`. The modules that rendered // those links on the homepage, product pages, category archives and // the cart are switched off since the theme change, so on the // high-traffic paths there is nothing left to click. // // A campaign-decorated landing is an input that does not depend on // any module rendering a link: whoever arrives on a first-party // decorated URL is attributable, including in a new tab or from a // shared link, where no click handler on this page ever ran. // // It has to be read here rather than in PHP: Cloudflare APO strips // `utm_*` from the cache key, so the origin is not guaranteed to see // them, while the browser always does. function campaignContext() { var params; try { params = new URLSearchParams(location.search); } catch (error) { return ''; } if (params.get('utm_source') !== 'fivemx') return ''; return cleanProperty(params.get('utm_content') || params.get('utm_campaign') || '', ''); } var landingContext = campaignContext(); if (landingContext) rememberJourneyContext(landingContext); function homeServerTilesVariant() { var now = Date.now(); if ( !config.home_server_tiles_experiment_start_ms || !config.home_server_tiles_experiment_end_ms || now < Number(config.home_server_tiles_experiment_start_ms) || now >= Number(config.home_server_tiles_experiment_end_ms) ) return ''; if (window.fivemxHomeServerTilesVariant === 'control' || window.fivemxHomeServerTilesVariant === 'premium') { return window.fivemxHomeServerTilesVariant; } var match = document.cookie.match(/(?:^|; )fivemx_home_server_tiles_variant=([^;]*)/); var variant = match ? decodeURIComponent(match[1]) : ''; return variant === 'control' || variant === 'premium' ? variant : ''; } function qbcoreMidTicketVariant() { var now = Date.now(); if ( !config.qbcore_mid_ticket_experiment_start_ms || !config.qbcore_mid_ticket_experiment_end_ms || now < Number(config.qbcore_mid_ticket_experiment_start_ms) || now >= Number(config.qbcore_mid_ticket_experiment_end_ms) ) return ''; if (window.fivemxQbcoreMidTicketVariant === 'control' || window.fivemxQbcoreMidTicketVariant === 'treatment') { return window.fivemxQbcoreMidTicketVariant; } var match = document.cookie.match(/(?:^|; )fivemx_qbcore_mid_ticket_variant=([^;]*)/); var variant = match ? decodeURIComponent(match[1]) : ''; return variant === 'control' || variant === 'treatment' ? variant : ''; } function experimentProps(props) { var variant = qbcoreMidTicketVariant(); if (variant) { props.experiment_id = cleanProperty(config.qbcore_mid_ticket_experiment, ''); props.experiment_variant = variant; } return props; } function productProps(product) { product = product || {}; var props = { product_id: String(product.product_id || ''), product_name: String(product.product_name || '') }; if (product.category) props.category = String(product.category); if (typeof product.price !== 'undefined') props.price = Number(product.price || 0); if (product.currency) props.currency = String(product.currency); if (product.product_segment) props.product_segment = cleanProperty(product.product_segment, ''); if (product.framework) props.framework = cleanProperty(product.framework, ''); if (product.price_band) props.price_band = cleanProperty(product.price_band, ''); if (window.fivemxServerOfferVariant) { props.experiment_variant = cleanProperty(window.fivemxServerOfferVariant, ''); } var homeVariant = homeServerTilesVariant(); if (homeVariant) props.home_experiment_variant = homeVariant; experimentProps(props); var context = journeyContext(); if (context) props.buyer_context = context; props.source_surface = context || cleanProperty(config.page_surface || '', 'unknown'); return props; } document.addEventListener('click', function(event) { var link = event.target && event.target.closest ? event.target.closest('[data-fivemx-shop-bridge]') : null; if (!link) return; // A bridge link without an explicit recommendation context used // to record nothing at all. Several surfaces render exactly that // shape, so fall back to the page's own buyer context before // giving up. var recommendationContext = config.page_surface === 'server-pack-buying-guide' ? config.page_surface : (link.getAttribute('data-fivemx-recommendation-context') || link.getAttribute('data-fivemx-buyer-context') || cleanProperty(config.buyer_context || '', '')); if (recommendationContext) { rememberJourneyContext(recommendationContext); } if (config.page_surface === 'server-pack-buying-guide' && !link.hasAttribute('data-fivemx-product-click')) { var routeTarget = link.getAttribute('href') || '/fivem-servers/'; var routePath = '/fivem-servers/'; try { routePath = canonicalPath(new URL(routeTarget, location.origin).pathname); } catch (error) { routePath = '/fivem-servers/'; } var routeFramework = routePath.indexOf('qbcore-server-packs') !== -1 ? 'qbcore' : (routePath.indexOf('esx-server-packs') !== -1 ? 'esx' : 'all'); var routeKey = 'server_pack_route_' + routePath; if (rememberRecently(routeKey, 1500)) { track('promotion_select', { promotion_id: 'server-pack-route', action: routeFramework, product_segment: 'server_pack', framework: routeFramework, source_surface: 'server-pack-buying-guide', source_path: canonicalPath(location.pathname), target_path: routePath }); } } }, true); document.addEventListener('click', function(event) { var link = event.target && event.target.closest ? event.target.closest('[data-fivemx-content-link]') : null; if (!link) return; track('content_link_click', { source_content_id: cleanProperty(link.getAttribute('data-source-content-id'), ''), target_content_id: cleanProperty(link.getAttribute('data-target-content-id'), ''), cluster: cleanProperty(link.getAttribute('data-cluster'), ''), placement: cleanProperty(link.getAttribute('data-placement'), '') }); }, true); document.addEventListener('click', function(event) { var link = event.target && event.target.closest ? event.target.closest('[data-fivemx-presale-contact]') : null; if (!link) return; var productId = cleanProperty(link.getAttribute('data-fivemx-product-id'), ''); var sourcePath = canonicalPath(location.pathname); track('presale_contact', { product_id: productId, product_name: cleanProperty(link.getAttribute('data-fivemx-product-name'), ''), product_price: Number(link.getAttribute('data-fivemx-product-price') || 0), source_path: sourcePath }); }, true); document.addEventListener('click', function(event) { var link = event.target && event.target.closest ? event.target.closest('[data-fivemx-home-action]') : null; if (!link) return; var action = cleanProperty(link.getAttribute('data-fivemx-home-action'), 'unknown'); var target = link.getAttribute('data-fivemx-home-target') || link.getAttribute('href') || '/'; var targetPath = target; try { targetPath = new URL(target, location.origin).pathname; } catch (error) { targetPath = '/'; } var promotionProps = { promotion_id: 'homepage-marketplace', action: action, surface: 'homepage', target_path: canonicalPath(targetPath), source_path: canonicalPath(location.pathname) }; var homeVariant = homeServerTilesVariant(); if (homeVariant) promotionProps.home_experiment_variant = homeVariant; track('promotion_select', promotionProps); }, true); document.addEventListener('click', function(event) { var action = event.target && event.target.closest ? event.target.closest('[data-fivemx-offer-action]') : null; if (!action) return; track('promotion_select', { promotion_id: cleanProperty(action.getAttribute('data-fivemx-offer-campaign'), 'unknown'), action: cleanProperty(action.getAttribute('data-fivemx-offer-action'), 'unknown'), surface: cleanProperty(action.getAttribute('data-fivemx-offer-surface'), 'unknown'), source_path: canonicalPath(location.pathname) }); }, true); document.addEventListener('click', function(event) { var link = event.target && event.target.closest ? event.target.closest('[data-fivemx-product-click]') : null; if (!link) return; var productId = link.getAttribute('data-fivemx-product-id') || ''; var productName = link.getAttribute('data-fivemx-product-name') || link.textContent || ''; var productPrice = link.getAttribute('data-fivemx-product-price') || ''; var role = link.getAttribute('data-fivemx-product-role') || ''; var recommendationContext = config.page_surface === 'server-pack-buying-guide' ? config.page_surface : (link.getAttribute('data-fivemx-recommendation-context') || link.getAttribute('data-fivemx-buyer-context') || config.buyer_context || ''); var target = link.getAttribute('data-fivemx-bridge-target') || link.getAttribute('href') || ''; var sourcePath = canonicalPath(location.pathname); var key = 'buyer_product_click_' + sourcePath + '_' + target + '_' + productId; if (!rememberRecently(key, 1500)) return; if (recommendationContext) rememberJourneyContext(recommendationContext); var props = { product_id: cleanProperty(productId, ''), product_name: cleanProperty(productName, 'unknown'), product_role: cleanProperty(role, ''), bridge_target: cleanProperty(target, ''), source_path: sourcePath, source_surface: cleanProperty(link.getAttribute('data-fivemx-source-surface') || config.page_surface || recommendationContext, 'unknown') }; if (productPrice !== '') props.price = Number(productPrice || 0); var productSegment = link.getAttribute('data-fivemx-product-segment') || ''; var framework = link.getAttribute('data-fivemx-framework') || ''; var priceBand = link.getAttribute('data-fivemx-price-band') || ''; if (productSegment) props.product_segment = cleanProperty(productSegment, ''); if (framework) props.framework = cleanProperty(framework, ''); if (priceBand) props.price_band = cleanProperty(priceBand, ''); if (recommendationContext) props.buyer_context = cleanProperty(recommendationContext, ''); var homeVariant = homeServerTilesVariant(); if (homeVariant) props.home_experiment_variant = homeVariant; experimentProps(props); track('select_product', props); }, true); if (config.is_buyer_page && config.buyer_context) { var buyerViewKey = 'buyer_page_view_' + location.pathname; if (rememberOnce(buyerViewKey)) { rememberJourneyContext(config.buyer_context); } } if (config.is_product && config.product && config.product.product_id) { var p = config.product; track('product_view', productProps(p)); } function checkoutBaseProps(extra) { var context = journeyContext(); var props = { item_count: Number(config.cart_count || 0), cart_total: Number(config.cart_total || 0), currency: cleanProperty(config.currency || 'USD', 'USD'), buyer_context: context, source_surface: context || cleanProperty(config.page_surface || '', 'checkout') }; var cartSegment = config.cart_segment || {}; ['product_segment', 'server_pack_count', 'server_pack_product_ids', 'framework', 'price_band'].forEach(function(key) { if (cartSegment[key]) props[key] = cleanProperty(cartSegment[key], ''); }); Object.keys(extra || {}).forEach(function(key) { props[key] = extra[key]; }); var homeVariant = homeServerTilesVariant(); if (homeVariant) props.home_experiment_variant = homeVariant; return experimentProps(props); } function selectedPaymentMethod() { var selected = document.querySelector('input[name="payment_method"]:checked'); var method = selected ? String(selected.value || '') : ''; method = method.toLowerCase().replace(/[^a-z0-9_-]/g, '').slice(0, 64); return method || 'unknown'; } function checkoutFieldGroup(target) { if (!target) return 'unknown'; var field = String(target.name || target.id || '').toLowerCase(); if (target.tagName === 'IFRAME') { var frameContext = String(target.title || target.getAttribute('aria-label') || '').toLowerCase(); if (/payment|card|stripe|secure/.test(frameContext) || target.closest('.payment_box, .payment_method_stripe_cc')) return 'payment'; } if (field.indexOf('email') !== -1) return 'email'; if (field.indexOf('first_name') !== -1 || field.indexOf('last_name') !== -1) return 'name'; if (field.indexOf('terms') !== -1) return 'terms'; if (field.indexOf('payment_method') !== -1 || field.indexOf('stripe') !== -1 || field.indexOf('card') !== -1) return 'payment'; if (field.indexOf('coupon') !== -1) return 'coupon'; if (/country|state|address|city|postcode|phone|company/.test(field)) return 'address'; return 'other'; } function checkoutErrorSummary(form) { var groups = {}; var fields = {}; if (form && form.querySelectorAll) { var invalid = form.querySelectorAll( '.woocommerce-invalid input, .woocommerce-invalid select, .woocommerce-invalid textarea, ' + 'input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"]' ); Array.prototype.forEach.call(invalid, function(field) { var identifier = cleanProperty(field.name || field.id || 'unknown', 'unknown'); fields[identifier] = true; groups[checkoutFieldGroup(field)] = true; }); var terms = form.querySelector('input[name="terms"]'); if (terms && !terms.checked) { fields.terms = true; groups.terms = true; } } var orderedGroups = ['email', 'name', 'address', 'terms', 'payment', 'coupon', 'other']; var firstGroup = 'payment_or_server'; for (var index = 0; index < orderedGroups.length; index += 1) { if (groups[orderedGroups[index]]) { firstGroup = orderedGroups[index]; break; } } var invalidFieldCount = Object.keys(fields).length; return { error_stage: invalidFieldCount > 0 ? 'validation' : 'payment_or_server', error_group: firstGroup, invalid_field_count: invalidFieldCount }; } if (config.is_checkout && !config.is_order_received && config.cart_count > 0) { var checkoutKey = 'fivemx_plausible_checkout_start_' + location.pathname + '_' + String(config.cart_count) + '_' + String(config.cart_total); if (rememberSessionOnce(checkoutKey)) { track('checkout_start', checkoutBaseProps()); } var checkoutForm = document.querySelector('form.checkout, form.woocommerce-checkout'); var checkoutFormStarted = false; var checkoutAttempt = 0; var checkoutAttemptResolved = 0; var checkoutOutcomeTimer = 0; document.addEventListener('focusin', function(event) { if (checkoutFormStarted || !event.isTrusted || !checkoutForm || !checkoutForm.contains(event.target)) return; if (!event.target.matches || !event.target.matches('input, select, textarea')) return; checkoutFormStarted = true; track('checkout_form_start', checkoutBaseProps({ first_field_group: checkoutFieldGroup(event.target) })); }, true); document.addEventListener('change', function(event) { if (!event.isTrusted || !event.target.matches || !event.target.matches('input[name="payment_method"]')) return; track('checkout_payment_method_selected', checkoutBaseProps({ payment_method: selectedPaymentMethod() })); }, true); function trackPlaceOrder() { if (!rememberRecently('fivemx_checkout_place_order', 1500)) return; checkoutAttempt += 1; track('checkout_place_order', checkoutBaseProps({ payment_method: selectedPaymentMethod(), attempt_index: checkoutAttempt })); window.clearTimeout(checkoutOutcomeTimer); checkoutOutcomeTimer = window.setTimeout(function() { if (checkoutAttemptResolved >= checkoutAttempt || document.visibilityState === 'hidden') return; if (checkoutForm && checkoutForm.classList.contains('processing')) return; checkoutAttemptResolved = checkoutAttempt; track('checkout_error', checkoutBaseProps({ error_stage: 'client_validation_or_blocked', error_group: checkoutFieldGroup(document.activeElement), invalid_field_count: 0, payment_method: selectedPaymentMethod(), attempt_index: checkoutAttempt })); }, 2500); } if (checkoutForm) { checkoutForm.addEventListener('submit', trackPlaceOrder, true); } if (window.jQuery) { window.jQuery(checkoutForm || 'form.checkout') .off('.fivemxCheckout') .on('checkout_place_order.fivemxCheckout', trackPlaceOrder); window.jQuery(document.body) .off('.fivemxCheckout') .on('checkout_error.fivemxCheckout', function() { window.setTimeout(function() { if (checkoutAttemptResolved >= Math.max(1, checkoutAttempt)) return; window.clearTimeout(checkoutOutcomeTimer); checkoutAttemptResolved = Math.max(1, checkoutAttempt); var summary = checkoutErrorSummary(checkoutForm); summary.payment_method = selectedPaymentMethod(); summary.attempt_index = Math.max(1, checkoutAttempt); track('checkout_error', checkoutBaseProps(summary)); }, 0); }) .on('checkout_place_order_success.fivemxCheckout', function() { window.clearTimeout(checkoutOutcomeTimer); checkoutAttemptResolved = Math.max(1, checkoutAttempt); track('checkout_submit_success', checkoutBaseProps({ payment_method: selectedPaymentMethod(), attempt_index: Math.max(1, checkoutAttempt) })); }); } } var lastCtaSource = ''; function trackProductCtaClick(source) { if (!config.is_product) return; var props = productProps(config.product || {}); if (!props.product_id && !props.product_name) return; lastCtaSource = cleanProperty(source, 'single_product_form'); props.currency = config.currency || 'USD'; props.source_path = canonicalPath(location.pathname); props.cta_source = lastCtaSource; var key = 'product_cta_' + (props.product_id || props.product_name || 'unknown') + '_' + props.source_path; if (!rememberRecently(key, 1500)) return; track('select_product', props); } document.addEventListener('click', function(event) { var target = event.target && event.target.closest ? event.target.closest('[data-fivemx-buy-now="1"], [data-fivemx-mobile-buy-button="1"], [data-fivemx-cylex-desktop-buy-button="1"], form.cart button.single_add_to_cart_button, form.cart input.single_add_to_cart_button') : null; if (!target) return; var source = 'single_product_form'; if (target.getAttribute('data-fivemx-buy-now') === '1') source = 'product_buy_now'; if (target.getAttribute('data-fivemx-mobile-buy-button') === '1') source = 'mobile_buy_bar'; if (target.getAttribute('data-fivemx-cylex-desktop-buy-button') === '1') source = 'cylex_desktop_sticky'; trackProductCtaClick(source); }, true); function trackAddToCart(product, source) { product = product || config.product || {}; var props = productProps(product); if (!props.product_id && !props.product_name) return; props.currency = product.currency || config.currency || 'USD'; props.source_path = canonicalPath(location.pathname); props.cta_source = cleanProperty(source, 'cart_form_submit'); var key = 'add_to_cart_' + (props.product_id || props.product_name || 'unknown') + '_' + props.source_path; if (!rememberRecently(key, 3000)) return; track('add_to_cart', props); } document.addEventListener('click', function(event) { var link = event.target && event.target.closest ? event.target.closest('[data-fivemx-direct-cart="1"]') : null; if (!link) return; var product = { product_id: link.getAttribute('data-fivemx-product-id') || '', product_name: link.getAttribute('data-fivemx-product-name') || '', price: Number(link.getAttribute('data-fivemx-product-price') || 0), currency: config.currency || 'USD' }; var recommendationContext = link.getAttribute('data-fivemx-recommendation-context') || ''; if (recommendationContext) rememberJourneyContext(recommendationContext); var directCartSource = link.getAttribute('data-fivemx-cart-source') || 'recommendation_direct_cart'; trackAddToCart(product, directCartSource); }, true); document.addEventListener('submit', function(event) { var form = event.target; if (!form || !form.matches || !form.matches('form.cart')) return; if (!lastCtaSource) trackProductCtaClick('cart_form_submit'); trackAddToCart(config.product, lastCtaSource || 'cart_form_submit'); }, true); if (window.jQuery) { window.jQuery(document.body).on('added_to_cart', function(event, fragments, cartHash, button) { var product = Object.assign({}, config.product || {}); var $button = window.jQuery(button || []); var id = $button.data('product_id'); if (id) product.product_id = String(id); trackAddToCart(product, 'ajax_add_to_cart'); }); } })({"is_product":false,"is_checkout":false,"is_order_received":false,"is_buyer_page":false,"buyer_context":"","page_surface":"","currency":"USD","cart_total":0,"cart_count":0,"cart_segment":[],"product":[],"analytics_events":{"experiment_exposure":"experiment_exposure","product_view":"product_view","search":"search","search_zero_results":"search_zero_results","select_product":"select_product","promotion_select":"promotion_select","add_to_cart":"add_to_cart","cart_confirmed":"cart_confirmed","checkout_start":"checkout_start","checkout_confirmed":"checkout_confirmed","checkout_form_start":"checkout_form_start","checkout_payment_method_selected":"checkout_payment_method_selected","checkout_place_order":"checkout_place_order","checkout_error":"checkout_error","checkout_submit_success":"checkout_submit_success","purchase":"purchase","download":"download","content_link_click":"content_link_click","presale_contact":"presale_contact"},"home_server_tiles_experiment_start_ms":1789250400000,"home_server_tiles_experiment_end_ms":1791669600000,"home_server_tiles_experiment":"homepage_server_tiles_2026_09","qbcore_mid_ticket_experiment_start_ms":1785694908000,"qbcore_mid_ticket_experiment_end_ms":1788114108000,"qbcore_mid_ticket_experiment":"qbcore_mid_ticket_merchandising_2026_08"}); </script> </body> </html> <!-- Performance optimized by Redis Object Cache. Learn more: https://wprediscache.com -->