# Exports & Events

This is the HUD's API for your other resources: notifications, progress bars, text prompts, status effects, the killfeed, stress, nitro, seatbelt and visibility.
Every export here is **client-side**. From server code, trigger one of the [events](#events) or a client event of your own that calls the export.

The resource is called `koja-hud`:

```lua
local hud = exports['koja-hud']
hud:sendNotify({ title = 'Bank', desc = 'Transfer complete' })
```

:::hint{type="warning"}
`exports['koja-hud']` fails silently if the name is wrong — no error, nothing on screen.
If you renamed the folder, every call must use the new name.
:::

## Summary

| Export | Returns | Purpose |
| --- | --- | --- |
| [`sendNotify(data)`](#sendnotify) | — | Show a notification |
| [`startProgressbar(data, cb)`](#startprogressbar) | — | Run a progress bar, call `cb(finished)` at the end |
| [`cancelProgressbar()`](#cancelprogressbar) | — | Cancel the running progress bar |
| [`isProgressbarActive()`](#isprogressbaractive) | `boolean` | Is a progress bar running |
| [`TextUI(data)`](#textui) | — | Show the "press E" prompt |
| [`HideUI()`](#hideui) | — | Hide it |
| [`ToggleHUD(visible)`](#togglehud) | — | Show or hide the whole HUD |
| [`HideComponent(name, hide)`](#hidecomponent) | — | Show or hide one component |
| [`HideComponents(map)`](#hidecomponents) | — | Several at once |
| [`SetStatusEffects(list)`](#setstatuseffects) | — | Replace the active status effects |
| [`AddStatusEffect(effect)`](#addstatuseffect) | — | Add or update one effect |
| [`RemoveStatusEffect(id)`](#removestatuseffect) | — | Remove one effect |
| [`AddKillfeed(killer, victim, weapon, distance, opts)`](#addkillfeed) | — | Add a killfeed entry |
| [`GetStress()`](#getstress) | `number` | Current stress, 0–100 |
| [`IsSeatbeltOn()`](#isseatbelton) | `boolean` | Is the seatbelt fastened |
| [`SeatbeltState(state)`](#seatbeltstate) | — | Set the seatbelt state |
| [`GetNitro()`](#getnitro) | `number` | Nitro left in the current vehicle |
| [`SetNitro()`](#setnitro) | — | Install nitro in the owned vehicle in front of the player |

## Notifications

### sendNotify

```lua
exports['koja-hud']:sendNotify({
    type = 'info',
    title = 'Bank',
    desc = 'You received <strong>$500</strong>',
    icon = 'fa-solid fa-building-columns',
    color = '#35c76c',
    time = 5000
})
```

| Field | Type | Default | Notes |
| --- | --- | --- | --- |
| `title` | string | `'Notify'` | Plain text |
| `desc` | string | `''` | May contain simple HTML, see below |
| `icon` | string | `'fas fa-info-circle'` | Any Font Awesome 6 class |
| `color` | string | `'#ffffff'` | Accent colour, hex |
| `time` | number | `5000` | How long it stays, in milliseconds |
| `type` | string | `'info'` | `'success'` and `'error'` replace `icon` and `color` with a green tick or a red mark; anything else keeps yours |

It always uses the HUD's notifications, whatever `KOJA.Notify` is set to, and is hidden if the player switched notifications off.

**HTML in `desc`.** Allowed tags: `b`, `strong`, `i`, `em`, `u`, `s`, `small`, `span`, `br`, `p`, `div`, `ul`, `ol`, `li`.
Allowed inline styles: `color`, `font-weight`, `font-style`, `text-decoration`, `opacity`.
Everything else — scripts, images, links, other attributes — is removed, so passing player-written text is safe.

```lua
exports['koja-hud']:sendNotify({
    title = 'Job',
    desc = "You earned <span style='color:#7cf14e'>$5,463</span> for finished work.",
    type = 'success'
})
```

#### From the server

There is no server export. Send a client event of your own:

```lua title="client.lua"
RegisterNetEvent('my-resource:notify', function(data)
    exports['koja-hud']:sendNotify(data)
end)
```

```lua title="server.lua"
TriggerClientEvent('my-resource:notify', source, { title = 'Garage', desc = 'Vehicle stored', type = 'success' })
```

## Progress bar

### startProgressbar

```lua
exports['koja-hud']:startProgressbar({
    label = 'Repairing',
    icon = 'fa-solid fa-wrench',
    time = 5,
    cancelable = true,
    animation = { dict = 'mini@repair', name = 'fixing_a_ped' },
    inputBlock = { keys = { 'W', 'A', 'S', 'D' } }
}, function(finished)
    if finished then
        -- repaired
    else
        -- cancelled
    end
end)
```

| Field | Type | Notes |
| --- | --- | --- |
| `label` | string | Text above the bar |
| `icon` | string | Font Awesome class |
| `time` | number | Duration in **seconds** |
| `cancelable` | boolean | The player can cancel with **X** |
| `animation` | table | Optional `{ dict, name }`. Loaded, played for the duration, stopped at the end |
| `inputBlock` | table | Optional `{ keys = { ... } }` — keys disabled while the bar runs |

The call returns immediately; the callback runs when the bar ends, with `true` if it completed and `false` if it was cancelled or replaced.
Starting a new progress bar while one is running replaces it, and the old callback gets `false`.

Key names for `inputBlock.keys`:
`ESC`, `F1`–`F3`, `F5`–`F10`, `~`, `1`–`9`, `-`, `=`, `BACKSPACE`, `TAB`, `Q`, `W`, `E`, `R`, `T`, `Y`, `U`, `P`, `[`, `]`, `ENTER`, `CAPS`, `A`, `S`, `D`, `F`, `G`, `H`, `K`, `L`, `LEFTSHIFT`, `Z`, `X`, `C`, `V`, `B`, `N`, `M`, `,`, `.`, `LEFTCTRL`, `LEFTALT`, `SPACE`, `RIGHTCTRL`, `HOME`, `PAGEUP`, `PAGEDOWN`, `DELETE`, `LEFT`, `RIGHT`, `TOP`, `DOWN`, `NENTER`, `N4`–`N9`, `N+`, `N-`.
Unknown names are ignored.

To wait for the result inline, wrap it in a promise:

```lua
local p = promise.new()
exports['koja-hud']:startProgressbar({ label = 'Searching', icon = 'fa-solid fa-magnifying-glass', time = 3 }, function(finished)
    p:resolve(finished)
end)
local finished = Citizen.Await(p)
```

### cancelProgressbar

```lua
exports['koja-hud']:cancelProgressbar()
```

Cancels the running bar; its callback gets `false`.

### isProgressbarActive

```lua
if exports['koja-hud']:isProgressbarActive() then return end
```

## Text UI

### TextUI

```lua
exports['koja-hud']:TextUI({
    input = 'E',
    type = 'Stash',
    desc = 'Open the stash'
})
```

| Field | Notes |
| --- | --- |
| `input` | The key shown in the box |
| `type` | Small heading above the text |
| `desc` | The text |

Calling it again replaces the prompt.
It does not listen for the key for you — check the key in your own loop and call [`HideUI`](#hideui) when the player walks away.

```lua
CreateThread(function()
    local shown = false
    while true do
        local near = #(GetEntityCoords(PlayerPedId()) - vec3(215.0, -810.0, 30.7)) < 2.0
        if near and not shown then
            exports['koja-hud']:TextUI({ input = 'E', type = 'Garage', desc = 'Take out a vehicle' })
            shown = true
        elseif not near and shown then
            exports['koja-hud']:HideUI()
            shown = false
        end
        if near and IsControlJustPressed(0, 38) then
            -- open your menu
        end
        Wait(near and 0 or 500)
    end
end)
```

### HideUI

```lua
exports['koja-hud']:HideUI()
```

## Visibility

### ToggleHUD

```lua
exports['koja-hud']:ToggleHUD(false) -- hide everything
exports['koja-hud']:ToggleHUD(true)  -- bring it back
```

Hides or shows the whole HUD — for cutscenes, character creation, cameras.
It does not touch the player's own **HUD Visibility** setting.

### HideComponent

```lua
exports['koja-hud']:HideComponent('carhud', true)
exports['koja-hud']:HideComponent('carhud', false)
```

Valid names: `status`, `carhud`, `progressbar`, `notify`, `textui`, `informations`.
Anything else is ignored (and logged with `KOJA.Debug = true`).
The change lasts until the resource restarts; the starting values come from `KOJA.HideComponents`.

### HideComponents

```lua
exports['koja-hud']:HideComponents({ status = true, informations = true })
```

Same names; components not in the table keep their state.

## Status effects

Small icons for active effects, each with an optional countdown ring.

```lua
{
    id = 'drunk',                    -- unique; adding the same id again updates it
    icon = 'fa-solid fa-wine-bottle',
    color = '#c77dff',               -- optional
    duration = 30                    -- optional, seconds, draws the countdown
}
```

:::hint{type="warning" title="Remove timed effects yourself"}
`duration` only draws the countdown ring and hides the icon when it reaches zero.
The effect stays in the list, so the next change to the list shows it again with a fresh countdown.
Call [`RemoveStatusEffect`](#removestatuseffect) when the effect really ends.
:::

### SetStatusEffects

```lua
exports['koja-hud']:SetStatusEffects({
    { id = 'drunk', icon = 'fa-solid fa-wine-bottle', color = '#c77dff', duration = 30 },
    { id = 'cold', icon = 'fa-solid fa-snowflake', color = '#6ab7ff' },
})
```

Replaces every effect added from code. Built-in effects (sprinting, swimming) are not affected.
`SetStatusEffects({})` clears them.

### AddStatusEffect

```lua
exports['koja-hud']:AddStatusEffect({ id = 'cold', icon = 'fa-solid fa-snowflake', color = '#6ab7ff' })
```

### RemoveStatusEffect

```lua
exports['koja-hud']:RemoveStatusEffect('cold')
```

## Killfeed

### AddKillfeed

```lua
exports['koja-hud']:AddKillfeed('Mike_R', 'Alex_92', 'fa-solid fa-gun', 48.0, { headshot = true })
```

| Argument | Type | Notes |
| --- | --- | --- |
| `killer` | string | Required |
| `victim` | string | Required |
| `weapon` | string | Font Awesome class for the weapon icon. Default `'fa-solid fa-skull'` |
| `distance` | number | Metres. Optional |
| `opts.headshot` | boolean | Shows the headshot marker |
| `opts.self` | boolean | Counts towards this player's killstreak |

The entry is dropped if it is further than the player's distance limit, and only shown if the player has the killfeed on (or is in PVP mode).
The HUD already adds the player's own kills; use this for everybody else's.

A server-side kill log can broadcast to everyone with the [`koja_hud:killfeed`](#koja_hudkillfeed) event.

## Stress

The HUD keeps a stress value from 0 to 100 and shows it as a bar.
**Nothing raises it automatically** — your resources decide what is stressful — and it is not saved: it starts at 0 on every join and resource restart.

### GetStress

```lua
local stress = exports['koja-hud']:GetStress()
```

To change it, use the [`koja-hud:addStress`](#koja-hudaddstress) and [`koja-hud:removeStress`](#koja-hudremovestress) events.

## Seatbelt

### IsSeatbeltOn

```lua
if exports['koja-hud']:IsSeatbeltOn() then ... end
```

Always `false` when `KOJA.Seatbelt.Enabled = false`.

### SeatbeltState

```lua
exports['koja-hud']:SeatbeltState(true)
```

Sets the HUD's seatbelt flag without a notification — for a resource that handles buckling itself and wants the icon and the exit lock to match.
Registered only when `KOJA.Seatbelt.Enabled = true`.

## Nitro

### GetNitro

```lua
local nitro = exports['koja-hud']:GetNitro() -- 0-100
```

Nitro in the vehicle the player is driving. `0` on foot, as a passenger, or in a vehicle the player does not own.

### SetNitro

```lua
exports['koja-hud']:SetNitro()
```

Starts installing nitro in the vehicle directly in front of the player (within about 5 metres).
The player must be on foot and own the vehicle, and its tank must be empty.
After a five-second animation the tank is filled to 100 and, when `KOJA.Nitro.Item` is set, one item is removed from the player on the server.
Each failure — in a vehicle, no vehicle, not the owner, already installed, no item — shows a notification.

Hook it to a usable item. The HUD removes the item itself, so do not remove it in your handler:

::::codegroup
```lua title="server.lua (ESX)"
ESX.RegisterUsableItem('nitro', function(source)
    TriggerClientEvent('my-resource:installNitro', source)
end)
```

```lua title="server.lua (QBCore)"
QBCore.Functions.CreateUseableItem('nitro', function(source)
    TriggerClientEvent('my-resource:installNitro', source)
end)
```

```lua title="client.lua"
RegisterNetEvent('my-resource:installNitro', function()
    exports['koja-hud']:SetNitro()
end)
```
::::

## Events

All of these are client events registered as net events, so they can be sent from the server with `TriggerClientEvent` or from another client script with `TriggerEvent`.

:::hint{type="info"}
Note the spelling: the stress events use a hyphen (`koja-hud:`), the others an underscore (`koja_hud:`).
:::

### `koja-hud:addStress`

```lua
TriggerClientEvent('koja-hud:addStress', source, 10)   -- server
TriggerEvent('koja-hud:addStress', 10)                 -- client
```

Adds to stress, capped at 100.

### `koja-hud:removeStress`

```lua
TriggerClientEvent('koja-hud:removeStress', source, 25)
```

Takes away from stress, never below 0.

### `koja_hud:killfeed`

```lua
TriggerClientEvent('koja_hud:killfeed', -1, {
    killer = 'Mike_R',
    victim = 'Alex_92',
    weapon = 'fa-solid fa-gun',
    distance = 48.0,
    headshot = true
})
```

Same fields as [`AddKillfeed`](#addkillfeed), plus `self`.

### `koja_hud:setStatusEffects`

```lua
TriggerClientEvent('koja_hud:setStatusEffects', source, {
    { id = 'wanted', icon = 'fa-solid fa-star', color = '#ffc933' }
})
```

Same as [`SetStatusEffects`](#setstatuseffects).

### `koja_hud:startTextUI`

```lua
TriggerClientEvent('koja_hud:startTextUI', source, { input = 'E', type = 'Shop', desc = 'Browse items' })
```

Same as [`TextUI`](#textui).

### `koja_hud:cancelTextUI`

```lua
TriggerClientEvent('koja_hud:cancelTextUI', source)
```

Same as [`HideUI`](#hideui).

## Internal events and callbacks

These exist for the HUD's own use. They are listed so you recognise them in logs; do not call them.

| Name | Kind | Purpose |
| --- | --- | --- |
| `koja_hud:setVehicleNitro` | server net event | Saves the nitro left in a vehicle. Only accepts a lower value than stored, and only from the owner |
| `koja_hud:getVehicleNitro` | koja-lib server callback | Reads a vehicle's nitro for its owner |
| `koja_hud:installNitro` | koja-lib server callback | Checks the item and fills the tank |

## Commands

| Command | Available | Does |
| --- | --- | --- |
| `/settings` | Always (`KOJA.SettingsCommand`) | Opens the settings menu |
| `/vehicle` | When `KOJA.VehicleMenu.Command` is set | Opens the vehicle menu while driving |
| `koja_vehiclemenu` | Always, bound to **U** | The key-mapped vehicle menu command |
| `+toggle_engine`, `+toggle_seatbelt`, `+toggle_cruisemode`, `+toggle_nitro` | When each feature is enabled | Key-mapped actions, registered through koja-lib |
| `/testnotify [type] [ms]` | `KOJA.Debug = true` | Sample notifications: `success`, `error`, `info`, `warning`, or all four |
| `/testprogress [seconds] [label]` | `KOJA.Debug = true` | A cancellable progress bar |
| `/testtextui [key] [text]` | `KOJA.Debug = true` | A text UI prompt |
| `/hidetextui` | `KOJA.Debug = true` | Hides it |
