Architecture du HUD¶
medusa-hud est l'unique propriétaire de la NUI du HUD joueur. Sa page transparente contient trois
zones indépendantes : la pile de statuts en haut à droite, l'inlay date/heure en bas à droite et un
cadre de navigation transparent autour de la minimap native en bas à gauche.
Le client surveille le menu pause toutes les 250 ms et ne transmet un message de visibilité que lors
d'un changement d'état.
Les systèmes métier restent découplés du rendu :
medusa-buffsapplique les effets et publiemedusa:hud:buffsaprès chaque synchronisation ;medusa-time-weathercalcule l'horloge autoritaire et publiemedusa:hud:datetimeuniquement lorsque la minute en jeu change.
Ces événements sont locaux au client et consommés par medusa-hud, qui seul appelle
SendNUIMessage. Les dépendances de ressources et l'ordre de server.cfg.template garantissent que
le consommateur est démarré avant ses producteurs. Ajouter un futur élément HUD consiste à ajouter
un événement local, son état de présentation et une zone visuelle dédiée, sans ajouter une nouvelle
NUI superposée.
La NUI repose volontairement sur la même structure minimale que l'ancien affichage des buffs, déjà
validé en jeu. FiveM fournit lui-même l'iframe fullscreen ; le document ne crée donc aucun wrapper
plein écran. body est transparent, sans color-scheme, opacité, transformation, filtre, backdrop
ou pseudo-élément global. Seuls les panneaux bornés #buffs et #clock portent un fond. Masquer le
HUD utilise display: none uniquement sur ses trois zones, sans modifier le canevas racine.
Le client positionne minimap, minimap_mask et minimap_blur avec
SetMinimapComponentPosition et les valeurs documentées dans common:/data/ui/frontend.xml : la
carte utilise (-0.0045, 0.002, 0.150, 0.188888), avec les géométries natives correspondantes du
masque et du flou. Le client reprend la méthode du cookbook FiveM : SetScriptGfxAlign('L', 'B') et
GetScriptGfxPosition convertissent le coin supérieur gauche frontend en coordonnées normalisées
d'écran, après application native du ratio et de la zone sûre. Aucun delta inverse n'est appliqué :
sur certains artifacts, la transformation calculée ne déplace pas le Scaleform du radar de façon
identique au cadre NUI et crée un décalage persistant.
La géométrie du cadre complète le coin renvoyé par le cookbook avec la largeur
1 / (4 * ratio) et la hauteur 1 / 5.674 de GetMinimapAnchor. Une extension de 16 px est ajoutée
uniquement au bord droit : elle couvre la marge visuelle du Scaleform constatée au-delà de sa largeur
théorique sans déplacer les trois autres bords déjà alignés. Le message NUI radarLayout transmet
ce rectangle normalisé ; le script web définit directement left, top, width et height du
cadre. Le cadre ne devient visible qu'après réception d'un rectangle valide.
Après le placement, un cycle du grand radar limité à un seul tick reconstruit le Scaleform pour que
la cartographie réapparaisse. SetMinimapClipType(0) rétablit immédiatement le masque rectangulaire.
La méthode Scaleform SETUP_HEALTH_ARMOUR(3) supprime les jauges natives de santé et d'armure. GTA
peut réinitialiser ce type durant le rendu ; ce seul override Scaleform est donc maintenu à chaque
frame lorsque le radar est visible, puis passe sur une attente de 250 ms avant le spawn ou pendant
la pause. Les natives multijoueur de visibilité et d'autorisation de la barre de capacité sont
également désactivées lorsqu'elles sont exposées par l'artifact client. Le repositionnement reste
appliqué uniquement au chargement, au spawn, à la fermeture du menu pause et lors d'un changement
de résolution, jamais à chaque frame. medusa-world-control reste propriétaire de l'affichage du
radar avant/après le spawn ; le HUD ne possède que sa géométrie et son habillage.
Le cadre #radar-shell ne possède aucun fond de panneau. Sa grille très légère, ses quatre angles,
ses télémétries et son réticule sont strictement bornés aux dimensions du radar. Il reste masqué
avant medusa:character:spawned et suit la visibilité globale pendant le menu pause.
Le script NUI appelle le callback ready après son chargement. Le client publie alors
medusa:hud:ready : medusa-time-weather invalide son cache de minute et redemande l'état serveur
s'il ne l'a pas encore, tandis que medusa-buffs republie son cache local. Ce handshake empêche la
perte des événements émis avant l'installation du listener JavaScript.
Le HUD expose aussi isReady. Au démarrage, chaque producteur attend cet export avant sa première
publication ; cette vérification couvre le cas où le callback NUI précède l'enregistrement de leurs
handlers locaux. L'événement reste nécessaire pour les redémarrages ultérieurs du HUD.
Suppression temporaire¶
L'événement local medusa:hud:setSuppressed masque/restaure la NUI et le radar sans changer l'état durable. L'ARPhone l'utilise pendant la capture photo afin que le HUD ne soit pas inclus dans l'image.
Adaptateur compteur véhicule¶
medusa-hud ne décide jamais si un véhicule ou un joueur sont autorisés. Il reçoit localement le
snapshot versionné medusa:hud:vehicleSpeedometer et le transmet directement au renderer natif.
Le contrat v3 contient visibilité, aperçu, préférence et télémétrie normalisée, sans état de
régulateur. Les contrats v1/v2 restent lisibles uniquement pour convertir une ancienne taille vers
80/100/120 et le bas-centre ; seules les préférences v3 sont émises et écrites.
client/vehicle_speedometer_native.lua est l'adaptateur de rendu unique. Les fichiers
stream/default.ytd, stream/id6.ytd et stream/id7.ytd sont byte-identiques au commit amont
1e150965034d575ea3eb3ffebe7bd0fa848daf79. Les trois sources
vendor/fivem-speedometer/skins/*.lua et la licence BSD 2-Clause sont elles aussi conservées
octet pour octet comme vérité vérifiable, mais ne sont jamais démarrées. L'adaptateur recopie leurs
constantes et leur ordre de dessin, puis appelle RequestStreamedTextureDict et DrawSprite avec
l'ancrage normalisé demandé, la compensation globale du ratio, la zone sûre et une échelle de
0,60 à 1,40 par pas de 0,05. Il ne charge ni thread, commande, KVP, default_middle, son, MPH ni
dépendance web du projet amont.
Une demande de dictionnaire est bornée à cinq secondes. Un échec produit un diagnostic unique,
remonte le thème à F5 et utilise CLASSIC comme repli lorsque seul D6 ou D7 est indisponible. F5
interdit alors Appliquer sur le thème fautif. Le HUD NUI ne dessine plus de compteur ni de badge
véhicule : il reste transparent et conserve seulement horloge, buffs et radar.
Les six aperçus F5 Jour/Nuit sont des PNG transparents lossless générés par
fivem/tools/export-speedometer-previews.py. L'outil vérifie d'abord les sept SHA-256 canoniques,
extrait les textures avec les dépendances épinglées de requirements-speedometer.txt, applique les
compositions exactes sans retouche et écrit un manifeste des hashes. La NUI Véhicules les affiche
avec un simple élément img; aucun SVG ou second cadran interprété n'existe.
Le renderer dérive une enveloppe conservatrice de toutes les coordonnées de chaque composition,
inclut le rayon diagonal des aiguilles et ignore uniquement les sentinelles amont hors écran. La
fonction exportée resolveSpeedometerGeometry sépare toujours la position désirée persistée de
la position rendue bornée. GetSafeZoneSize() et GetAspectRatio(false) sont intégrés au clamp :
un changement de résolution déplace temporairement le rendu sans PATCH et la position désirée
réapparaît lorsqu'elle redevient compatible. La géométrie est mise en cache tant que thème,
échelle, position, ratio et zone sûre ne changent pas.
La télémétrie reste locale, bornée à 50 ms et dédupliquée. Le
mode d'éclairage auto résout Nuit à partir de 20 h, avant 6 h ou avec les phares/pleins phares ;
day/night sont forcés. Le harness non-runtime
fivem/tests/fixtures/vehicle-speedometer-visual.html vérifie les cartes F5 et la transparence NUI
avec des snapshots synthétiques. Il ne peut pas capturer les DrawSprite natifs :
les comparaisons du compteur réellement streamé restent une recette FiveM à effectuer aux
résolutions et ratios prévus.
Le compteur natif, la barre de placement et leurs pseudo-éléments restent bornés. html et body déclarent
explicitement background: transparent !important, [hidden] reste prioritaire et aucun
color-scheme n'est autorisé. Le test global nui-transparency.test.mjs parcourt toutes les
ui_page Medusa afin d'empêcher le retour du backdrop noir.
Enrichissement énergie¶
La télémétrie locale fournit type/niveau/autonomie/moyenne aux trois compositions existantes. Les bornes de fiabilité, flags et performances sont détaillés dans Énergie des véhicules.