# esx_hud (/docs/addons/esx_hud)

esx_hud is the default heads-up display for ESX Legacy. It shows health, armor, hunger, thirst, stamina and oxygen bars, cash and bank balance, the job label, the current weapon with ammo, voice range, and a vehicle speedometer with fuel, damage, indicators and persistent mileage. Use it as-is or as a reference for building your own HUD.

## Overview [#overview]

| | |
| --- | --- |
| Resource | `esx_hud` (version 1.10.2) |
| Side | Client UI (NUI) with a small server part for mileage |
| Dependencies | `esx_lib`, `es_extended`, `esx_status`, `oxmysql` |
| Optional | `esx_cruisecontrol` (seatbelt and cruise control state), `LegacyFuel`, `pma-voice` or `saltychat` |
| Database | Adds `owned_vehicles.mileage` automatically |

The UI ships prebuilt in `web/dist`. You only need Node.js if you change the React source in `web/src` and rebuild it.

## Installation [#installation]

<Steps>
<Step>
### Place the resource [#place-the-resource]

Put `esx_hud` in your addons folder, for example `resources/[esx_addons]/esx_hud`.
</Step>
<Step>
### Ensure it after its dependencies [#ensure-it-after-its-dependencies]

```bash title="server.cfg"
ensure oxmysql
ensure esx_lib
ensure es_extended
ensure esx_status
ensure esx_hud
```
</Step>
<Step>
### Let it migrate the database [#let-it-migrate-the-database]

On first start the server calls `xLib.schema.ensureMileage()`, which adds `mileage DECIMAL(10,2) NOT NULL DEFAULT 0.00` to `owned_vehicles`. Check the console for `[esx_hud] 1.16.0 mileage schema ready`. If the migration fails, mileage tracking is disabled and the error is printed.
</Step>
</Steps>

## Configuration [#configuration]

All options live in `shared/config.lua`. The locale comes from the `esx:locale` convar (default `en`).

### Config.Disable [#configdisable]

Set a key to `true` to turn a feature off.

| Key | Default | Description |
| --- | --- | --- |
| `Status` | `false` | Health, armor, hunger, thirst, stamina and oxygen bars |
| `Vehicle` | `false` | Speedometer and the whole mileage system (server side too) |
| `Weapon` | `false` | Weapon name, image and ammo |
| `Position` | `false` | Street and zone display |
| `Voice` | `false` | Voice range indicator |
| `Money` | `false` | Cash and bank display |
| `Info` | `false` | Info panel (logo, job, online players) |
| `IndicatorSound` | `true` | Turn-signal sound |
| `IndicatorSeatbeltSound` | `false` | Seatbelt warning sound |
| `VehicleHandlers` | `false` | Indicator and engine keybinds |
| `MinimapOnFoot` | `false` | `true` hides the minimap while on foot |
| `Needle` | `false` | Legacy option; the current speedometer is digital |
| `StatusPercent` | `false` | Percentage numbers on status bars |
| `CenterStatuses` | `true` | `true` places statuses above the minimap, `false` stacks them on the left |

### Config.Default [#configdefault]

| Key | Default | Description |
| --- | --- | --- |
| `ServerLogo` | `""` | Logo URL; empty uses the bundled ESX logo |
| `ServerName` | `""` | Server name in the info panel |
| `ServerTagline` | `""` | Tagline under the server name |
| `AccentColor` | `""` | Primary theme color; empty uses the ESX theme from esx_lib |
| `Kmh` | `true` | `true` for km/h, `false` for mph |
| `PassengerSpeedo` | `false` | Show the speedometer to passengers too |

### Config.Colors [#configcolors]

Three color groups are passed straight to the UI as CSS values:

- `Info`: `money-text-color` (`#0aad20`), `bank-text-color` (`#666666`), `job-text-color` (`#fb9b04`)
- `Status`: `healthBar`, `armorBar`, `drinkBar`, `foodBar`, `staminaBar`, `oxygenBar`
- `Speedo`: about 25 keys such as `segment-color`, `speedo-progress-color`, `fuel-icon-color` and `speedo-background-color`

Players can also change colors and units in-game through `/hudsettings`. Those changes only affect their own client.

## Commands and keybinds [#commands-and-keybinds]

| Command or key | Description |
| --- | --- |
| `/hud`, `/togglehud` | Toggle the HUD for yourself |
| `/hudsettings` | Open the settings panel (colors, unit, minimap, cinematic mode) |
| `LEFT` / `RIGHT` arrow | Left or right indicator (also on an attached trailer) |
| `UP` arrow | Hazard lights |
| `N` | Toggle the engine |

The keybinds are registered through `xLib.addKeybind`, so players can rebind them in the FiveM key settings. They are not registered when `VehicleHandlers` or `Vehicle` is disabled. Indicators are ignored in aircraft.

## Client exports [#client-exports]

### HudToggle [#hudtoggle]

```lua
exports.esx_hud:HudToggle(state)
```

| Name | Type | Description |
| --- | --- | --- |
| `state` | `boolean` | `true` shows the HUD, `false` hides it |

The same function is registered as the net event `esx_hud:HudToggle`, so the server can call it with `TriggerClientEvent('esx_hud:HudToggle', playerId, false)`.

```lua title="client/cutscene.lua"
exports.esx_hud:HudToggle(false)
-- play your cutscene
exports.esx_hud:HudToggle(true)
```

### SeatbeltState and CruiseControlState [#seatbeltstate-and-cruisecontrolstate]

```lua
exports.esx_hud:SeatbeltState(state)
exports.esx_hud:CruiseControlState(state)
```

Both take a `boolean` and only update the icons. esx_cruisecontrol calls `SeatbeltState` through its `Config.HudResource` setting. If you use a different seatbelt script, call these exports from it.

### GetCurrentMileage [#getcurrentmileage]

```lua
local mileage, kmh, loaded = exports.esx_hud:GetCurrentMileage()
```

Returns the mileage of the vehicle the player is driving, whether it is in km (`kmh`), and whether the value was already loaded from the server. Before it is loaded the first value is `nil`. Only available when `Config.Disable.Vehicle` is `false`.

## Server exports [#server-exports]

Mileage is cached on the server per plate (trimmed and uppercased). Only vehicles that exist in `owned_vehicles` are cached as "owned"; unowned vehicles get a random value that is never saved.

### GetMileage [#getmileage]

```lua
local miles = exports.esx_hud:GetMileage(plate)
```

Returns the cached mileage in miles (rounded to two decimals) for an owned vehicle, or `nil` if the plate is not cached yet.

### GetMileages [#getmileages]

```lua
local map = exports.esx_hud:GetMileages({ 'ABC 123', 'XYZ 999' })
-- map['ABC 123'] = 1520.4
```

Takes an array of plates and returns a table keyed by plate. Plates without a cached value are left out. esx_garage uses this to show mileage in its menu.

## Events [#events]

| Event | Side | Description |
| --- | --- | --- |
| `esx_hud:HudToggle` | client (net) | Show or hide the HUD |
| `esx_hud:UpdateMileage` | client (net) | Server sends the loaded mileage to the driver |
| `esx_hud:UnitChanged` | client (local) | Fired when the player switches km/h and mph in settings |
| `esx_hud:EnteredVehicle` | server (net) | `(plate, kmh)` driver entered; loads mileage |
| `esx_hud:ExitedVehicle` | server (net) | `(plate, mileage, kmh)` driver left; updates cache |
| `esx_hud:UpdateVehicleMileage` | server (net) | `(plate, mileage, kmh)` used by esx_garage on store |

esx_hud listens to `esx_status:onTick` for hunger and thirst, `esx:setAccountMoney` for money, `esx:setJob` for the job, `esx:pauseMenuActive` to hide itself in the pause menu, and `esx:enteredVehicle` / `esx:exitedVehicle` from es_extended.

<Callout type="warn" title="Client-trusted mileage">
The three server net events take the plate and mileage from the client without checking that the player actually drives that vehicle. A modified client can rewrite the stored mileage of any owned vehicle. The value is clamped to 0 – 99,999,999.99, so it cannot break the database, but do not use mileage for anything valuable (insurance payouts, resale price) without your own server-side checks.
</Callout>

## Saving mileage [#saving-mileage]

The server writes cached mileage of owned vehicles to `owned_vehicles.mileage`:

- every 5 minutes
- when `esx_hud` stops
- 10 seconds before a txAdmin scheduled restart, and on txAdmin shutdown

The value is always stored in miles. With `Kmh = true` the client shows it multiplied by 1.61.

## Integration tips [#integration-tips]

- **Voice:** pma-voice and saltychat are detected automatically. For any other voice resource, edit `client/voice.lua` and send `xLib.nui.send({ type = "VOICE_RANGE", value = index })`.
- **Fuel:** LegacyFuel is read through its export. Other fuel scripts work if they set the native fuel level.
- **Status bars:** hunger and thirst come from the `hunger` and `thirst` statuses of [esx_status](/docs/addons/esx_status). Custom statuses are not displayed.
- **Other HUDs:** if you replace esx_hud, keep esx_cruisecontrol happy by pointing its `Config.HudResource` at your resource or removing the export call.

## Common issues [#common-issues]

- **HUD is blank or missing:** `web/dist` is missing (you cloned the source without the build). Download the release, or run `npm install` and `npm run build` in `web`.
- **"Setup your custom voice resource" in the console:** neither pma-voice nor saltychat is started. Set `Config.Disable.Voice = true` or add your own voice handler.
- **Mileage stays at 0 after restart:** the schema migration failed (check the console) or the vehicle is not in `owned_vehicles`.
- **Indicators do nothing:** another resource uses the arrow keys, or `VehicleHandlers` is disabled. Players can rebind under Settings, Key Bindings, FiveM.

## Related [#related]

- [esx_status](/docs/addons/esx_status)
- [esx_cruisecontrol](/docs/addons/esx_cruisecontrol)
- [esx_garage](/docs/addons/esx_garage)
- [esx_lib](/docs/core/esx_lib)
- [Client events](/docs/es_extended/events/client)
