Interact system
3D interaction system + NPC dialogue engine, with zero dependency. Place an interaction anywhere on the map: on an entity, a free coordinate, or an NPC you spawn from the same call. No ox_lib, no framework, no server side setup.
What it does
No dependency at all
Since 1.1.0 the resource ships its own DUI handling, proximity points and wait helpers in `bridges/compat.lua`, written on plain natives. Nothing to install first, nothing to keep in load order. If you already run ox_lib and would rather it did that work, set `Config.UseOxLib = true` and uncomment one line in the manifest.
Technical
specifications
Everything you
get
-
Fifteen locale files, shipped filled
Your players read the script in their own language from the first start, and the files sit outside escrow so you can edit any line in production. Honest note: they are translated and reviewed by us, not proofread by native speakers of all fifteen. Tell us what reads wrong in yours and it gets fixed.
-
Everything tunable in config.lua
Default label, key, distances, icon and color of a point, named colors, the key label to control index map, the ped used when an entry omits one, spawn range, and which HUD is hidden during a dialogue. All of it left escrow in 1.1.0.
-
Three working examples
An ATM watcher registered by model hash with a two-key menu, an NPC with a full branching dialogue and a GPS waypoint, and a multi-bind dance point. Real files in `config/`, delete them once you have your own.
-
Discord support and lifetime updates
Access to the support channel, and every future update at no extra cost. No premium tier, no paid add-on.
Integration guide
Installation
-
Drop the resource
Grab the script from your Tebex account, then copy the
avenida_interact/folder intoresources/[avenida]/on your server. -
Enable in server.cfg
Add
ensure avenida_interact. Nothing has to load before it: since 1.1.0 the resource has no dependency, so load order does not matter. -
Set your defaults
Open
config/config.luaand tune what applies to every point: label, key,showIconandcanInteractdistances, icon, color, named colors, ped spawn range, andConfig.Hudto pick which HUD is hidden during a dialogue. -
Remove the demos
The examples in
config/entities/,config/peds/andconfig/positions/are live as long as their files are there. Delete the ones you do not want, the manifest globs those folders so there is nothing else to edit. -
Test the hot reload
Start the server, then type
/restart avenida_interactin game. Icons disappear and come back cleanly, and points registered by your own resources survive, without restarting your session.
Quickstart
Your first interaction point in 30 seconds
Create a `myscript/client.lua` in your own resource and paste this. A cyan marker appears at 30m, the "E - Hello" prompt unrolls at 2m. The only thing that has to be running is avenida_interact itself.
-- myscript/client.lua
exports.avenida_interact:positionRegister({
coords = vec3(-265.0, -963.6, 31.2),
showIcon = 30.0, -- marker fades in at 30m
canInteract = 2.0, -- label unrolls at 2m
hintIcon = 'interact', -- see the icon list below
hintColor = '#22d3ee', -- hex, or an alias from Config.Colors
message = 'Hello',
bind = 'E',
onInteract = function()
TriggerEvent('chat:addMessage', { args = { 'Hello, world!' } })
end,
})API Reference
Public exports grouped by domain. Each row shows the call signature and what it does, not how it does it.
Interact Points
positionRegister
exports.avenida_interact:positionRegister(cfg) --> idRegisters a point on fixed coordinates. Takes every visual field (
hintIcon,hintColor,showIcon,canInteract,offsetZ,blips) pluschoices[]for several keys on the same point.canInteractaccepts a number or a function, so you can gate the prompt on a job, an item or a cooldown. Returns an id.pedRegister
exports.avenida_interact:pedRegister(cfg) --> idSpawns a configured NPC (model,
animDictandanimNameor a scenario, blip), attaches a point on it and returns its index. The ped is invincible, will not flee and will not ragdoll. It spawns and despawns aroundConfig.PedSpawnRange, 50m by default. SetrandomComponents = falseon a named vendor, otherwise every player sees a different outfit.pedRemove
exports.avenida_interact:pedRemove(idx)Added in 1.1.0. Despawns a ped registered with
pedRegisterand drops its registration, so a temporary quest giver can leave when the quest is over.entityRegister
exports.avenida_interact:entityRegister(cfg) --> idAttaches a point onto one existing entity, passed as
cfg.entity. Supportscfg.boneto hook the prompt on a bone instead of the entity center. Use it for something another script spawned: a vehicle, a placed prop, a dropped item.entityRegisterByHash
exports.avenida_interact:entityRegisterByHash(hash, cfg)Passive watcher: the config applies to every entity of that model, the ones already streamed and the ones that appear later. A single thread covers all registered hashes and sweeps every 5s. This is what you want for ATMs, vending machines and doors, rather than a coordinate list to maintain.
entityRemove
exports.avenida_interact:entityRemove(idx)Detaches the point returned by
entityRegister. The entity itself is left alone.interactCreate
exports.avenida_interact:interactCreate(cfg) --> idRuntime point, created and removed on demand. Use it when the point only exists for a while: a mission objective, a bag on the ground, a body to search.
interactRemove
exports.avenida_interact:interactRemove(id)Removes a point created by
interactCreate, and its blip if it declared one.unlockLastInteract
exports.avenida_interact:unlockLastInteract()A point locks itself once used, so a held key does not fire it twice. Call this at the end of your action to re-arm it. If the player is still in range the prompt comes straight back, otherwise it waits for them to walk in again.
Prompt API
HandleTextUI
exports.avenida_interact:HandleTextUI(id, data) --> duiHandlerCreates or updates a standalone 3D bubble, without any interaction point behind it. For when you want to drive visibility from your own thread. Returns the handler you pass to
Draw3DSprite.Draw3DSprite
exports.avenida_interact:Draw3DSprite({ duiHandler, coords, maxDistance, hintOnly? })Draws the bubble in world space from a render thread, un-stretched against the screen aspect. With
hintOnly = trueonly the marker is drawn, which is the long distance state of a normal point.CloseTextUI
exports.avenida_interact:CloseTextUI(id)Hides a bubble but keeps its DUI in memory, so reopening is instant.
RemoveTextUI
exports.avenida_interact:RemoveTextUI(id)Removes a bubble for good and frees its DUI. Use it when you know it will not come back.
RemoveTextUIs
exports.avenida_interact:RemoveTextUIs()Removes every active bubble. Called for you when the resource stops.
IsDuiVisible
exports.avenida_interact:IsDuiVisible() --> booleanTrue while a prompt is on screen. Read it to keep your own prompts from stacking on top of an interaction.
Key handler
HandleHoldTextUI
exports.avenida_interact:HandleHoldTextUI(id, data) --> duiHandlerThe layer the points are built on: it draws a prompt at
Coordsand watches its key from a 50ms manager thread.datatakesBindToHold(control index),DistanceHold,Coords,ChoicesUIandChoicesCtrlfor a multi-key prompt,onCallback(id)andcanInteract(id, dist). It fires on press with a 500ms debounce, and your callback runs in apcallso an error on your side does not break the prompt.CloseHoldTextUI
exports.avenida_interact:CloseHoldTextUI(id)Hides the prompt without destroying the instance, for a clean exit when the player leaves the zone.
RemoveHoldTextUI
exports.avenida_interact:RemoveHoldTextUI(id)Destroys one instance and frees its DUI.
RemoveHoldTextUIs
exports.avenida_interact:RemoveHoldTextUIs()Destroys every active instance.
Recipes
Real-world copy-paste examples. Drop them into your own resource, tweak the values, ship.
The simplest case: a point on coordinates, with its blip declared in the same table. The marker shows at 30m, the label at 2m. Drop this in any client file of your own resource.
exports.avenida_interact:positionRegister({
coords = vec3(149.5, -1040.4, 29.4),
showIcon = 30.0,
canInteract = 2.0,
hintIcon = 'bank',
hintColor = 'blue',
message = 'Use the ATM',
bind = 'E',
onInteract = function()
TriggerEvent('myserver-banking:openATM')
end,
blips = {
sprite = 277,
color = 2,
scale = 0.8,
text = 'ATM',
display = 4,
},
})The watcher registers your config once per model and applies it to every matching prop, the ones already streamed and the ones that appear later. Each choice carries its own label, color and `condition`, so the robbery only appears when your police script says so. Mind the field name: a choice uses `condition`, not `canInteract`.
local ATM_PROPS = {
'prop_atm_01', 'prop_atm_02', 'prop_atm_03', 'prop_fleeca_atm',
}
for _, prop in ipairs(ATM_PROPS) do
exports.avenida_interact:entityRegisterByHash(prop, {
canInteract = 1.2,
offsetZ = 1.0,
hintIcon = 'bank',
hintColor = 'blue',
choices = {
{
bind = 'E',
message = 'Use the ATM',
onInteract = function()
TriggerEvent('myserver-banking:atmUse')
end,
},
{
bind = 'G',
message = 'Rob the ATM',
hintColor = 'red',
condition = function()
return exports['myserver-police']:hasEnoughCops(2)
end,
onInteract = function(entity)
TriggerServerEvent('myserver-robbery:startATM', NetworkGetNetworkIdFromEntity(entity))
end,
},
},
})
endA complete quest giver: the ped spawns with its animation and blip, and the dialogue answers run whatever you want, here the native `SetNewWaypoint`. `changeDialog` replaces the text and the answers, so you nest as deep as the conversation needs. `randomComponents = false` keeps her outfit identical for every player.
exports.avenida_interact:pedRegister({
coords = vec4(-1393.81, -1064.09, 3.17, 266.09),
model = 'a_f_y_vinewood_04',
animDict = 'anim@amb@waving@male',
animName = 'ground_wave',
randomComponents = false,
message = 'Talk with Maria',
showIcon = 10.0,
canInteract = 3.0,
hintIcon = 'talk',
hintColor = 'gold',
blips = { sprite = 119, color = 50, text = 'Lumberjack', scale = 0.8 },
dialogue = {
name = 'Maria',
startMsg = 'Hello, are you ready to start your shift?',
elements = {
{
label = 'Yes, where do I start?',
action = function(changeDialog, close)
SetNewWaypoint(-584.01, 5491.59)
changeDialog('The forest is on your GPS now.', {
{ label = 'Got it!', action = function(_, close) close() end },
})
end,
},
{
label = 'I\'ll come back later',
action = function(_, close) close() end,
},
},
},
})Troubleshooting
- You do not. Since 1.1.0 `bridges/compat.lua` implements DUI creation, proximity points and the wait helpers on plain natives, and the `@ox_lib/init.lua` line is commented out in the manifest. If you would rather route that through ox_lib, set `Config.UseOxLib = true` and uncomment that line. Both paths are supported, the native one is the default.
- First, range: `showIcon` defaults to 4m in `Config.Defaults`, which is short if you expected a long distance marker, so pass your own value. Second, if you used `entityRegister` the entity has to exist at call time, while `entityRegisterByHash` waits for it, which is what you want for game props. Third, set `Config.Debug = true` to print internal errors to the client console.
- A choice reads `condition`, not `canInteract`. `canInteract` is the field of the point itself, where it takes a number or a function. Inside `choices[]` the gate is `condition = function() ... end`, and a choice whose condition returns false is simply not drawn.
- Any hex value such as `#22d3ee`, or a name from `Config.Colors`, which ships with `red`, `blue`, `green`, `gold`, `purple` and `white`. That table is escrow exempt, so add your server palette to it and use your own names everywhere. An unknown `hintIcon` is drawn as text, so an emoji works as a one-off icon.
- That was fixed in 1.1.0. The DUI texture is now locked to 1920x1080 and un-stretched at draw time against the real screen aspect, and the icon no longer changes size with distance. Dialogue answer boxes also gained height above 2560x1440. Update the resource if you are still on 1.0.x.
- Ownership is tracked with `GetInvokingResource()`, so a point belongs to whatever resource called the export. If you registered from a shared handler running in another resource context, the cleanup follows that other resource instead. Wrap the call in a function of the resource that owns the point. Since 1.1.0 points are also purged when a resource starts, so a restart no longer leaves ghosts behind.
- You do not have to plug it into anything: the resource knows nothing about your framework and never talks to your server. Read the player job or grade inside `canInteract` or a choice `condition`, and call your own events from `onInteract`. Anything that runs on your framework runs behind these two functions, unchanged.
- Measured at 0.00ms idle with 100 points. Drawing only happens inside `showIcon` range, and the key watcher runs at 50ms for instances that are in range, so thousands of points across the map cost nothing as long as they are not all stacked in one street.
What buyers say
5.0 2 verified reviews
Revoria very good scriptwriters a reactive and competent listening team I recommend go there with your eyes closed!!
theara Best script, best support! Fast support and friendly!
FEATURED Avenida TeamBarber shop
A barbershop staged like a scene, with a camera the player actually controls. The character walks in, sits down, and the barber gets to work while an orbit camera frames the head. Hair, beard, overlays and the full skin-detail set, previewed live before a single dollar is spent.
FEATURED Avenida TeamClothing store
A clothing store with saved outfits, company wardrobes and an editor that prices the catalogue from inside the game. Every component and every prop, bought one garment at a time or as a whole look, with a server-side ledger that stops anyone wearing what they never paid for.
FEATURED Avenida TeamCore Skin (3 in 1)
Barber shop, tattoo parlour and clothing store in one FiveM resource. 1615 tattoos, every clothing component and prop, the whole head and skin set, spread across 36 shops. One interface, one camera, one purchase flow, and one thing to install on ESX, QBCore, vRP or standalone.