How Integrations Work#
Backrooms reaches every third-party resource through a small, unencrypted bridge file, and picks which one to use by looking at what is running when it starts. The server console prints the result on every start:
[qs-backrooms:INFO] Started - framework: qb | inventory: ox_inventory | target: ox_targetLayer | Supported | Without it |
|---|---|---|
Framework |
| Standalone: money and items kept by the script itself, identified by license. Enough to try it on an empty server. |
Inventory |
| A Backrooms bag inside each run (12 slots, 18 kg). What a player escapes with goes to your framework's inventory. |
Target |
| Containers and bodies use the |
Ambulance |
| The script revives players itself. |
Notifications |
| ox_lib, which is a dependency anyway. Inside a run, the script's own notifications are always used. |
3D labels |
| Plain drawn text above entrances and fallen survivors. |
HUD |
| Your HUD stays on screen during a run until you wire it into |
Voice |
| Talking makes no noise. |
Phone |
| Only the phone keys are blocked. |
Quests |
| No quests. |
Database |
| Required. The only one. |
Every optional integration degrades silently. A missing resource makes that part fall back, not throw — which is why the start line matters. Run only one inventory and one target: with two of the same kind started, which one is picked is not guaranteed.
Frameworks#
Each framework has a client and a server bridge in custom/esx/, custom/qb/ and custom/standalone/. The server file handles money, items, revives, metadata and who counts as an admin; the client file knows whether the player is loaded and whether they are dead. Qbox runs on the QBCore bridge.
Detection is a small table at the top of config/config.lua. If you renamed your framework's resource, add the new name on the left:
-- config/config.lua
local frameworks = {
['es_extended'] = 'esx',
['qb-core'] = 'qb',
['qbx_core'] = 'qb',
['my-core'] = 'qb', -- your renamed resource
}
Config.Framework = DependencyCheck(frameworks) or 'standalone'The bridges call the framework by its usual name — exports['es_extended'] or exports['qb-core'] at the top of each file — so change it there too. The inventories and targets tables just below work the same way.
Standalone#
Without a framework, Backrooms keeps a record per player in the resource's own storage — cash, bank, items and metadata — identified by their license. Escape rewards land there, and admins are whoever holds the command ace. It is meant for testing; on a live server, run it with your framework.
Inventories#
Items found during a run go straight into the player's own inventory, under ox_inventory's own weight and slot limits. Every usable Backrooms item is registered with ox_inventory at start — the console says Registered 11 usable items with ox_inventory — so it can be used from the normal inventory as well as the Backrooms bag.
The same as ox_inventory: the items live in the player's inventory, and the usable ones are registered through your framework's usable items. qs-inventory also gets the three Backrooms quests below.
ESX's default inventory, qb-inventory and the rest run a Backrooms bag during the run: 12 slots and 18 kg, opened with F2. Escaping with loot hands the items to your framework's inventory, where they are registered as usable items with ESX or QBCore.
Targets#
With ox_target or qs-target, loot containers and bodies get target options — Search and Search the body — that only work while the player is inside a run. Exits, lockers and entrances always use the [E] prompt. Both bridges live in client/custom/target.lua.
Ambulance Jobs and Revives#
No edits to your ambulance job are needed.
Framework | How death is noticed | How a player is revived |
|---|---|---|
ESX |
|
|
QBCore · Qbox | The |
|
Standalone | The player's health. | Resurrected by the script. |
Two settings decide how the Backrooms and your ambulance job share a death: Wake up inside after dying — and its chance — under Getting in, and Revive on the way out, which you turn off if your ambulance job should take care of players who come out dead.
Using a different ambulance script? Add its revive event to framework:revive in your framework's bridge — custom/esx/client.lua and server.lua, or the custom/qb/ ones.
Notifications, Labels and Your HUD#
client/custom/main.lua is where the Backrooms talks to the screen, and every function in it is yours to change:
Function | What it does |
|---|---|
| Inside a run, the script's own notifications. Outside, |
| The labels above entrances and fallen survivors — |
| Called with |
To hide your own HUD during a run, add its export to SetCustomHud:
-- client/custom/main.lua
function SetCustomHud(visible)
if GetResourceState('qs-interface') == 'started' then
exports['qs-interface']:ToggleHud(visible)
end
-- your HUD
if GetResourceState('my-hud') == 'started' then
exports['my-hud']:SetVisible(visible)
end
endPhones and Other Scripts During a Run#
While a player is inside, the Backrooms blocks the phone keys and fires a client event telling qs-smartphone to stand down — and again when the run ends. The list also sits on the player's state bag, LocalPlayer.state['qs-backrooms:blocked'], for as long as the run lasts:
AddEventHandler('qs-backrooms:client:blockResource', function(resource, blocked)
-- resource: 'qs-smartphone'
-- blocked: true when the run starts, false when it ends
end)For any other phone, radio or menu, check exports['qs-backrooms']:IsInBackrooms() before opening it, or listen to the server events in Commands and Exports.
Discord Logs#
Entries, descents, escapes, deaths, admin actions and new entrances can be posted to a Discord channel. Set the webhook as a convar in server.cfg — set, not setr, so it never reaches a client:
set qs_backrooms_webhook "https://discord.com/api/webhooks/..."
set qs_backrooms_webhook_name "The Backrooms" # optional
set qs_backrooms_webhook_avatar "https://..." # optionalLog | Sent when |
|---|---|
Backrooms Entry | A player enters, with the level and the way in. |
Backrooms Admin Entry | An admin or a script sends a player in. |
Backrooms Descent | A player goes deeper. |
Backrooms Escape | A player escapes, with the cash they were paid. |
Backrooms Death | A player dies inside, with the level and the cause. |
Backrooms Admin Removal |
|
Backrooms Door Placed | An admin places an entrance. |
Each embed names the player with their identifier. Logs are queued and sent one at a time, so a busy server never floods Discord. Everything is built in DiscordLog() in server/custom/main.lua, which your own code can call too.
Quests#
With qs-inventory running, each player is given three Backrooms quests the first time they enter:
Quest | Completed by |
|---|---|
Enter the Unknown | Entering the Backrooms. |
Escape the Madness | Escaping at least once. |
Descend Deeper | Reaching the deepest floor. Progress grows with every level. |
Their titles, descriptions, rewards and required levels are at the top of server/custom/main.lua.
Money and Items#
Escape rewards are paid as cash through framework:addMoney in your framework's server bridge, and machine prices are taken through framework:removeMoney, from cash or bank. Items go through framework:addItem, removeItem and getItemCount in the same file, which hand off to ox_inventory or qs-inventory when either runs. A different money account or item handling is changed there. server/custom/main.lua registers the usable items at start, and offers GiveItem, RemoveItem, HasItem and Notify helpers for your own additions.
Languages#
41 languages ship in locales/: English, Spanish, French, German, Portuguese, Italian, Dutch, Polish, Turkish, Russian, Ukrainian, Arabic, Chinese, Japanese, Korean and more. Pick one in the settings panel (General → Language) and it applies to every player at once, or set the default for every Quasar resource with setr qs:locale "de".
To change a text, edit its line in that language's JSON file. A key missing from a translation falls back to English, and the console names it on start.



