sd-interact puts the interaction on the thing itself. Look at something you can use and a small prompt opens on it: an icon on the spot, what it does, and the key that does it. Several options stack on a drum you scroll. Hold options draw an outline round the tile as you hold, and on a controller the key becomes the pad button. It has its own API, and it can also answer ox_target, qtarget and qb-target calls, so the scripts you already run use it without changing a line.
Download · Docs · Store · Discord
Works together: sd-interact · sd-gunracks
If you're enjoying sd-interact and want to support my work, consider picking up a script from Samuel's Development. Every purchase helps me keep building and improving free resources like this one.
Recorded from the prompt page itself (the same page the game draws), over a rendered room.
The rooms are rendered in Blender. The prompts are captured from the page and placed exactly where the game draws them: the tile on the point, at the size the default config draws at 4K. Click an image for the full 1920×1080 version.
- On the thing, not on the screen. The prompt is painted into the game's own frame at the point (an off-screen page drawn with
DrawSprite). It stays pinned to the world with no lag, and it renders at the screen's own resolution, so its text stays sharp. - Quiet until you need it. Only the point nearest the middle of the screen opens. Other points in range show as small dots, a ring once you're close enough, and dots that crowd together merge into one. A prompt behind a wall doesn't open.
- Press, scroll, hold. Options stack on a drum, and the one on the point is the one the key uses. An option can ask to be held: an outline runs round its tile as you hold and runs back if you let go. It can carry a second line, or change its label as things change ("Rack Assault Rifle").
- Keyboard and controller. Confirm, next and previous are FiveM key mappings (E and the wheel, the d-pad on a pad), so every player can rebind them in Settings > Key Bindings > FiveM. The prompt shows whichever device you're using.
- Anything you can point at. Coordinates, local or networked entities (on an offset or a bone), every entity of some models, or every vehicle, ped, object or player nearby.
- A stand-in for the target you use. Turned on, it answers
exports.ox_target,exports.qtargetandexports['qb-target']with prompts: zones, entities, models, bones, global options, item, job and gang checks, and every way of handling an option.
| Layer | Supported |
|---|---|
| Frameworks | Any. Job, gang and item checks read QBox, QBCore or ESX when one is running, and ox_inventory for items |
| Input | Keyboard and mouse, controller |
| Languages | English, Danish, Swedish (Locale in configs/config.lua) |
| Stands in for | ox_target (its 1.17 API), qtarget, qb-target (its 5.5 API) |
| Needs | ox_lib. Client only: no server script, no database |
Download sd-interact.zip from the latest release and unzip it into your resources folder: it is the resource with its prompt page already built, ready to drop in. Start it after ox_lib, and before the resources that add prompts:
ensure ox_lib
ensure sd-interactImportant
Download the sd-interact.zip asset, not Source code (zip) or the green Code button. Those are the source, without the built page: the resource would start, but no prompt would ever draw until you build it yourself.
Distances, the default keys, the prompt's size and the dots are in configs/client/.
The full guide is at docs.samueldev.shop/resources/interact:
| Installation | Start order, a first prompt to check it works, rebinding keys |
| Adding prompts | Points, distances, where the prompt sits, options, who sees them, what they do |
| Examples | A shopkeeper, every ATM, a car's boot that says Open or Close, police-only options, item checks, server entities, moving over from ox_target |
| Client exports | Every export with its parameters and what it returns |
| Configuration | Every option in configs/client/ |
| Replacing ox_target / qb-target | Answering their exports, what is supported, the known differences |
A first prompt, to see the shape of it:
exports['sd-interact']:addLocalEntity(ped, {
offset = vec3(0.0, 0.0, 0.3),
options = {
{ label = 'Browse the shop', icon = 'fa-solid fa-basket-shopping', serverEvent = 'myshop:open' },
{ label = 'Rob the till', icon = 'fa-solid fa-sack-dollar', hold = 3000, groups = { ballas = 0 }, onSelect = robTill },
},
})Options take ox_target's handler fields (onSelect, export, event, serverEvent, command) and groups, so option tables move over as they are.
Scripts written for a target resource can use prompts without being changed. Name the ones to answer in your server.cfg, before ensure sd-interact, then take the real resource out of your server (two resources answering one export fight):
setr sd_interact:replace "ox_target,qtarget"
ensure sd-interactScripts that list ox_target as a dependency also need something by that name to start: an empty stand-in resource or a provide line. Both, every supported export, and the known differences are on Replacing ox_target / qb-target.
The repository is the source: the built prompt page (web/build) is not committed, and each release builds it into its zip. To run a clone, or after changing the page, build it with Node.js (LTS):
cd web
npm ci
npm run build # what the game draws (web/build)
npm run dev # the page in a browser: /#mock runs through every state (#mock&step=0..4 freezes one)A source zip unpacks to sd-interact-main: rename the folder to sd-interact, the name its exports are called by. #shot=<messages> shows one state, given as the JSON messages the game sends, for pictures like the ones above. CANVAS and ANCHOR in web/src/Prompt.tsx must match Canvas and Anchor in configs/client/draw.lua.
lua tests/run.lua runs focus picking, the point registry, and the ox_target, qtarget and qb-target layers offline under stock Lua 5.4: option conversion, handler data, checks, removal and the self target.
GPL-3.0. Fonts, icons and other third-party material are listed in THIRD_PARTY_NOTICES.md.



