> For the complete documentation index, see [llms.txt](https://fantasy-scripts.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://fantasy-scripts.gitbook.io/docs/lib-interactions-radial-menu-menus-and-notifications/exports.md).

# Exports

Every ox\_lib function works exactly as it always has — `lib.notify`, `lib.registerContext`, `lib.progressBar`, `lib.inputDialog`, `lib.callback` and the rest. They simply look different now. Nothing to change in your scripts.

The one addition is the interaction system below.

## Interaction points

The `[E] LABEL` prompts that appear in the world. You register a point once, and ox\_lib draws it, decides when it is close enough, and runs what you gave it when the player presses the key.

Walk near a point and a small ring appears. Get closer and the ring becomes the prompt. Press **E** to use it. If a point has more than one option, scroll (or the arrow keys) to pick between them.

Everything here is client side.

***

### Where a point can sit

| Function                          | Sits on                                  |
| --------------------------------- | ---------------------------------------- |
| `lib.addInteraction`              | A fixed coordinate                       |
| `lib.addLocalEntityInteraction`   | An entity on this player's machine       |
| `lib.addEntityInteraction`        | A networked entity, by net id or handle  |
| `lib.addEntityBoneInteraction`    | A bone of an entity, such as a boot      |
| `lib.addModelInteraction`         | Every prop of a model, such as every ATM |
| `lib.addGlobalVehicleInteraction` | Every vehicle                            |
| `lib.addGlobalPedInteraction`     | Every ped                                |
| `lib.addGlobalPlayerInteraction`  | Every player                             |

Each returns an **id**, which is what you keep if you ever want to remove or change the point later.

### What they all take

| Field         | What it is                                                                                                                                                                     |
| ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `options`     | The list of things the point offers. One option on its own is fine, without a list around it.                                                                                  |
| `distance`    | How far away the ring shows. Default **2.5**                                                                                                                                   |
| `interactDst` | How close before the prompt shows and E works. Default **1.2**                                                                                                                 |
| `offset`      | Moves the point, as a `vec3`. On a coordinate it is added; on an entity it is in the entity's own directions, so `vec3(0.0, 1.0, 0.5)` is a metre in front and half a metre up |
| `coords`      | **Model points only.** Keeps the point to the props standing at these spots, instead of every prop of that model. One `vec3` or a list                                         |
| `radius`      | **Model points only.** How far a prop may stand from one of those spots and still count. Default **3.0**                                                                       |
| `name`        | A name for the point itself, for your own use                                                                                                                                  |

### An option

| Field                               | What it is                                                        |
| ----------------------------------- | ----------------------------------------------------------------- |
| `label`                             | The words on the prompt                                           |
| `name`                              | A name for this one option, so it can be removed on its own       |
| `canInteract(entity, coords, args)` | Return false and the option is not shown                          |
| `action(entity, coords, args)`      | Runs when pressed                                                 |
| `event`                             | Triggered instead, on this client                                 |
| `serverEvent`                       | Triggered instead, on the server                                  |
| `command`                           | Run instead, through `ExecuteCommand`                             |
| `args`                              | Anything you want passed along to whichever of the above you used |

Use **one** of `action`, `event`, `serverEvent` or `command`. They are tried in that order.

`event` and `serverEvent` both receive a single table:

```lua
{ entity = ..., coords = ..., args = ..., name = ... }
```

On `serverEvent`, `entity` is the **net id**, not the handle, and it is `nil` when the point is not on a networked entity.

> **It is `action`, not `onSelect`.** `onSelect` is ox\_target. An option with `onSelect` registers without complaint and then does nothing when pressed.

***

### A door you can lock

The plainest case: a point on a coordinate.

```lua
lib.addInteraction({
    coords = vec3(-1080.2, -248.5, 37.8),
    distance = 3.0,      -- ring from three metres
    interactDst = 1.5,   -- prompt from a metre and a half
    options = {
        {
            label = 'Lock door',
            name = 'door:lock',
            action = function()
                TriggerServerEvent('myscript:lockDoor', 'jewelry_front')
            end,
        },
    },
})
```

### Two options on one point

The player scrolls between them. `canInteract` decides which are shown at all, so the same point can offer different things to different people.

```lua
lib.addInteraction({
    coords = vec3(441.8, -981.9, 30.7),
    options = {
        {
            label = 'Go on duty',
            canInteract = function() return not LocalPlayer.state.onDuty end,
            serverEvent = 'police:setDuty',
            args = { on = true },
        },
        {
            label = 'Go off duty',
            canInteract = function() return LocalPlayer.state.onDuty end,
            serverEvent = 'police:setDuty',
            args = { on = false },
        },
    },
})
```

### Every ATM in the world

One registration covers every prop of those models, wherever it is, including ones that stream in later.

```lua
lib.addModelInteraction({
    models = { 'prop_atm_01', 'prop_atm_02', 'prop_atm_03', 'prop_fleeca_atm' },
    distance = 2.5,
    interactDst = 1.0,
    options = {
        { label = 'Use cash machine', event = 'fs-banking:client:openAtm' },
    },
})
```

#### Only the ones in your shops

A model point is **every prop of that model in the world**. That is right for a cash machine and wrong for the till on your shop's counter — the same till stands in every shop on the map, and they would all light up.

Give `coords` and it only attaches to the props standing at those spots:

```lua
lib.addModelInteraction({
    model = 'prop_till_01',
    coords = vec3(25.0, -1347.0, 29.5),   -- one spot, or a list of them
    radius = 3.0,                          -- how far a prop may be and still count
    options = {
        { label = 'Pay at the till', event = 'fs-shops:client:pay' },
    },
})
```

All of your shops in one registration:

```lua
local COUNTERS = {
    vec3(25.0, -1347.0, 29.5),
    vec3(-47.0, -1758.0, 29.4),
    vec3(373.0, 325.0, 103.6),
}

lib.addModelInteraction({
    model = 'prop_till_01',
    coords = COUNTERS,
    options = { { label = 'Pay at the till', event = 'fs-shops:client:pay' } },
})
```

`radius` is three metres unless you say otherwise, which is loose enough that the coordinate does not have to be exact — stand at the counter, note where you are, and it will find the till. Without `coords` nothing changes: the point still attaches to every prop of that model, as it always did.

**Two other ways to reach one prop**, if they suit you better:

* `lib.addInteraction` at the counter's coordinate. Nothing to do with the model at all, and the simplest thing that works for a till that never moves.
* `GetClosestObjectOfType(coords, 2.0, model, false, false, false)` for the handle, then `lib.addLocalEntityInteraction` on it. Exact, but the prop has to be streamed in at the moment you register, so it needs to run when a player is nearby rather than once at startup.

#### One model, a different spot for the prompt

If one model needs the prompt in a different place, give the models one at a time with their own offsets:

```lua
lib.addModelInteraction({
    modelData = {
        { model = 'prop_atm_01' },
        { model = 'prop_vend_soda_01', offset = vec3(0.0, -0.4, 0.4) },
    },
    options = { { label = 'Use', action = function(entity) print(entity) end } },
})
```

### A vehicle's boot

The bone is where the prompt sits, so it follows the car and stays on the right part of it. `entity` is passed to everything the option runs.

```lua
local plate = GetVehicleNumberPlateText(vehicle)

lib.addEntityBoneInteraction({
    entity = vehicle,
    bone = 'boot',
    offset = vec3(0.0, 0.0, 0.1),
    options = {
        {
            label = 'Open boot',
            action = function(entity)
                SetVehicleDoorOpen(entity, 5, false, false)
            end,
        },
    },
})
```

### A ped you spawned

Use the local one for peds only you can see, and the networked one for anything shared with other players.

```lua
lib.addLocalEntityInteraction({
    entity = shopkeeper,
    offset = vec3(0.0, 0.0, 0.2),   -- a little above the head
    options = {
        { label = 'Browse shop', event = 'fs-shops:client:open', args = { shop = 'tools' } },
    },
})

lib.addEntityInteraction({
    netId = netId,                  -- a handle works too
    options = { { label = 'Search', serverEvent = 'myscript:search' } },
})
```

### Every vehicle, every ped, every player

These need no entity at all — ox\_lib finds them. Keep `canInteract` tight, or the option shows on everything.

```lua
lib.addGlobalVehicleInteraction({
    bone = 'bonnet',
    options = {
        {
            label = 'Check engine',
            canInteract = function(entity)
                return GetVehicleEngineHealth(entity) < 900.0
            end,
            action = function(entity) TriggerEvent('mechanic:inspect', entity) end,
        },
    },
})

lib.addGlobalPlayerInteraction({
    options = {
        {
            label = 'Give handcuffs',
            canInteract = function() return LocalPlayer.state.onDuty end,
            serverEvent = 'police:cuff',
        },
    },
})
```

***

### Taking them away again

```lua
local id = lib.addInteraction({ ... })

lib.removeInteraction(id)                  -- the whole point
lib.removeInteractionOption(id, 'door:lock')  -- one option by its name
lib.removeInteractionByEntity(entity)      -- every point on that entity
lib.updateInteraction(id, newOptions)      -- swap the options out
lib.disableInteractions(true)              -- hide every point for now
```

Removing the last option of a point removes the point with it.

Points belonging to a resource are **not** cleaned up for you when it stops, so remove them yourself if the entity is going away:

```lua
AddEventHandler('onResourceStop', function(resource)
    if resource == GetCurrentResourceName() then lib.removeInteraction(id) end
end)
```

***

### Settings

`ox_lib/interact.lua`, and they apply to every script on the server.

| Setting                                  | What it does                                                                     |
| ---------------------------------------- | -------------------------------------------------------------------------------- |
| `enabled`                                | Off turns every point off. The functions stay, so nothing breaks                 |
| `key` / `control`                        | The letter on the badge and the control that uses it. `38` is E                  |
| `defaultDistance` / `defaultInteractDst` | Used by any point that does not set its own. **2.5** and **1.2**                 |
| `uppercase`                              | Labels written in capitals                                                       |
| `crosshair`                              | A dot in the middle of the screen while points are near                          |
| `hoverRadius`                            | How near the middle of the screen a point must be to be the selected one         |
| `disable`                                | Hide everything while dead, in a vehicle, cuffed, or while a menu has the cursor |

Colours come from `ox_lib/theme.lua`: `text` for the label, `key` and `keyText` for the badge.

#### replaceTextUI is off, on purpose

`lib.showTextUI('...')` hands over a line of text and nothing else — there is no coordinate in it. With `replaceTextUI` on, ox\_lib has to invent a position from where the player happens to be standing and looking, which is different on every visit, so the prompt drifts.

A prompt that belongs to a place should be registered at that place with `lib.addInteraction`. That draws on the exact coordinate and never moves. Leave `replaceTextUI.enabled = false`.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://fantasy-scripts.gitbook.io/docs/lib-interactions-radial-menu-menus-and-notifications/exports.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
