Everything below, without the walkthrough. Scroll past it if this is your first time.
Paste one of the three files below. The patched version comes back with the block already in the right place, correctly indented, ready to save over the original.
The things that actually go wrong, and what each one means.
ox_lib text UI is HALF installed (1 of 2 lines found).
Add the second line from the block above.
Config.Intercept…
to false so we stay out of its way.
ensure dispersia_interactions below them in server.cfg.open/config.lua./interactions_test in game. It draws three sample rows first, so you can see
the panel itself is alive, then reports every integration point — read from the real file
on the server, not guessed from what the prompt looks like.
Config.InterceptAk47, InterceptOxTarget and
InterceptQbTarget ship false. The blocks are documented
and the code is there; the native interaction mode, which owns selection
as well, is what makes them worth turning on.
false for every reticle message.
ox_target it must
replace the existing local SendNuiMessage = SendNuiMessage line in
client/main.lua. In qb-target it must be at the very top of
client.lua, above anything that could cache the original.
ak47_target is a provider that runs on top of qb-target or ox_target, not a target
system of its own. Patch whichever of those two it sits on — that is where the options
actually go out.
dispersia_interactions has to stay exactly that — no version suffix, no copy
marker. Also confirm the folder sits directly inside resources.
textui.lua in the same folder — something
like textui - backup.lua. ox_lib loads
resource/**/client/*.lua as a glob, so a spare copy is loaded too and redefines the
same functions. Delete it; do not just rename it.
Config.Debug = true in open/config.lua and every row carries a
[source] tag showing which interceptor produced it, which usually identifies the
problem in one screenshot.
Still stuck?Open a ticket in Discord. Include your framework, the console error, and what you already tried.
OPEN A TICKETMost servers never open this. If you patched ox_lib and your target system, every prompt on your server already draws in one style — there is nothing to call.
Showing a prompt from your own script:
exports['dispersia_interactions']:Show('E', 'Open shop')
Each resource owns its own row and cannot overwrite another’s. Hide() clears the one you registered. Everything below is for the rare case where that is not enough.
| exports['dispersia_interactions']:Show(key, text, ctx?) | Show a keyed row. ctx is optional: pass { ctx = 'shop' } when one resource needs several rows at once. Without it the row is keyed by the calling resource. |
| exports['dispersia_interactions']:Hide(ctx?) | Clear the row this resource registered, or the one under that ctx. |
| exports['dispersia_interactions']:HideAll() | Clear every row immediately, whoever registered it. For death, a menu opening, a cutscene. |
| exports['dispersia_interactions']:ShowPrompt(key, label, coords?) | A prompt for scripts with no target system. Pass coords and it hides itself once the player walks past Config.HideDistance. |
| exports['dispersia_interactions']:HidePrompt() | Hide it by hand — from onExit, or when the action stops being valid for a reason distance cannot see. |
| exports['dispersia_interactions']:SetTheme(opts) | Restyle at runtime, no restart. Every key optional — pass only what changes. |
| exports['dispersia_interactions']:Intercept(kind, ...) | The one export every inserted line calls. kind is 'textui', 'textuihide', 'ak47', 'oxtarget' or 'qbtarget'. Returns true when we drew it and false when we did not — so the caller knows whether to continue. |
| returns false when… | the message is an aiming reticle, the kind is unknown, that interception is switched off in the config, or anything inside us threw. In every one of those cases the original renders exactly as it always did. |
| text parsing | 'textui' receives the raw ox_lib string and splits it into rows — including several keys in one string. |
| blur | Backdrop blur in px. Default 0 — a blurred layer costs GPU on every frame it is visible, so it ships off. |
| keyBgL · keyBgR | Key box gradient, left and right. |
| keyBorder | Key box right edge — the strongest line in the shape. |
| tailStart · tailMid | The fading tail behind the label. |
| textColor | Label colour. Default '#ffffff'. |
| tailWidth | Maximum tail width as CSS. Default '300px'. |
| '[E] - Open shop' | The common one. |
| '[E] - Open [H] - Rob' | Several keys in one string — becomes two rows. |
| '[E] - Open\n[H] - Rob' | Same, on separate lines. Literal \n from locale files is handled too. |
| 'E - Open shop' | No brackets. Keys up to 6 characters. |
| anything else | Drawn as-is with key E, rather than dropped. |
| Config.MaxRows | Rows on screen at once. Default 6; the oldest is dropped first. |
| Config.TargetKey | Key label on rows from a target system. Default 'LMB' — targets are aimed and clicked, not pressed, so there is no keyboard key to report. |
| Config.InterceptOxLib | ox_lib text UI. Needs both lines in textui.lua. |
| Config.InterceptAk47 | ak47_target. Option list replaced, reticle untouched. |
| Config.InterceptOxTarget | ox_target, and with it all of QBox. |
| Config.InterceptQbTarget | qb-target. |
| Config.HideDistance | Auto-hide distance for a coords-bound prompt. Default 3.5. |
| Config.DistanceCheckInterval | How often that check runs, in ms. Default 250. |
| Config.Debug | Adds a [source] tag to every row. Leave false on a live server. |
| /interactions_test | Draws three sample rows, then reports every integration point. The verdict is read from the real file on the server, never guessed from what the prompt looks like. |
| Idle cost | 0.00 ms. No Wait(0) loops anywhere in the resource. |
| Distance watcher | One thread, alive only while a coords-bound prompt is on screen, waking every 250 ms. Nothing runs otherwise. |
| Resource cleanup | When a resource stops, its rows go with it — automatically, without that resource having to remember. |