How Integrations Work#
Camera never talks to your framework or inventory directly. Each one is reached through a small bridge file, and the right bridge is picked at start by looking at what is already running. The console line qs-camera v2.0.0 started (esx / ox) says which two it chose.
Layer | Supported | Without it |
|---|---|---|
Framework |
| Standalone: players are recognised by their license and named by their FiveM name. |
Inventory |
| Required. With none of these running, the qs-inventory bridge is assumed and nothing can be given or used. |
Screenshots |
| Required. No photo or card can be taken. |
Notifications and progress bars |
| ox_lib, which is a dependency anyway. |
HUD |
| Your HUD stays on screen while a camera is up. The game's own HUD and radar are always hidden. |
Quests |
| No quests; nothing else changes. |
Database |
| Required. |
Qbox is served by the QBCore bridge through
qbx_core's QBCore compatibility, and uses ox_inventory for its items.
Overriding Detection#
Detection reads two small tables at the top of shared/config.lua. The left side is a resource name, the right side the bridge it uses. If your framework or inventory runs under another name, add it:
-- qs-camera/shared/config.lua
local frameworks = {
['es_extended'] = 'esx',
['qb-core'] = 'qb',
['qbx_core'] = 'qb',
['my-core'] = 'qb', -- a renamed QBCore
}
local inventories = {
['ox_inventory'] = 'ox',
['qs-inventory'] = 'qs',
['qb-inventory'] = 'qb',
['ps-inventory'] = 'qb',
['lj-inventory'] = 'qb',
}Detection only sees resources that are already started, so anything you want found must be above ensure qs-camera in server.cfg. Run only one inventory from the list: with two started at once, which one wins is not guaranteed.
Notifications and Progress Bars#
Messages — You loaded a new roll of film, Nobody is close enough — and the progress bars for repairing and loading film use qs-interface when it is running and ox_lib otherwise. Both are plain functions in client/custom/framework/<your framework>.lua — SendTextMessage and ProgressBar — so another notification resource is a few lines:
-- client/custom/framework/esx.lua (or qb.lua / standalone.lua)
function SendTextMessage(msg, kind)
-- kind is 'success', 'error' or 'inform'
exports['my-notify']:Show(msg, kind)
endHiding the HUD#
While a viewfinder, an album or the board editor is on screen, your HUD is hidden, and it comes back once nothing needs the screen any more. Which HUDs are hidden is a list in client/custom/hud.lua. qs-interface ships in it, and adding yours is one entry:
-- client/custom/hud.lua
HudResources = {
['qs-interface'] = function(visible)
exports['qs-interface']:ToggleHud(visible)
end,
['my-hud'] = function(visible)
exports['my-hud']:SetVisible(visible) -- false hides it, true brings it back
end,
}An entry for a resource that is not running is skipped, so a list of several HUDs costs nothing. A hook that throws is caught and reported in F8, and never leaves a player stuck behind a camera.
Floating Prompts#
The [E] Take down and [E] Board prompts on walls and boards are drawn by DrawText3D in client/custom/prompt.lua. Replace its body to draw them your own way. It is called every frame while the player stands in range, so a text UI that is shown and hidden — rather than drawn each frame — needs to remember whether it is already on screen.
Using Items#
Items become usable through your framework and inventory on their own, with one exception: ox_inventory calls an export named in the item's definition. That is the server = { export = 'qs-camera.useItem' } line in every ox_inventory definition on Inventory Items — leave it out and the item cannot be used.
Whatever the route, the server checks that the player really holds the item in that slot before anything happens, and ignores a second use of the same item within a third of a second.
Quests with qs-inventory#
With qs-inventory running, Camera gives every player five quests. They live in server/custom/missions.lua, which you may edit — titles, descriptions, rewards and levels.
Quest | Goal |
|---|---|
Shocking Experience | Get shocked when a camera gives out on you. |
Camera Repairman | Bring a broken camera back to life. |
Camera Enthusiast | Take at least 20 photos — digital photos and printed cards both count. |
Photo Viewer | Look at 5 photos. |
Collector of Moments | Store 5 photos in an album. |
Photo Hosting#
The two cameras upload differently, which is worth knowing when something fails:
| Digital photos | Instant cards |
|---|---|---|
Who uploads | The player's game, through | The server, after the card is composed on the player's screen. |
Where to |
| The same |
Checked | The answer must be a valid web address. | The address must belong to a host on the Uploads list, and the image must be under about 3 MB. |
The Uploads list in the settings panel holds cdn.discordapp.com, media.discordapp.net and *.fivemanage.com by default. Keep it that way unless the service you upload to answers with a different address; an empty list accepts any https host.
Adding a Backend#
Supporting a framework or inventory that is not on the list is deliberately small: one copied file per side, plus one line.
Copy the closest bridge
Inventories live in
server/custom/inventory/andclient/custom/inventory/; frameworks inserver/custom/framework/andclient/custom/framework/. None of them is encrypted. Copy the one nearest to yours —ox.lua, say — and name it after your resource.Change the calls inside
Each bridge only runs when it is the chosen one, and fills four functions with your resource's own exports:
lua if Config.Inventory ~= 'myinv' then return end function GetItems(src) ... end function AddItem(src, item, count, slot, metadata) ... end function RemoveItem(src, item, count, slot) ... end function SetItemMetaData(src, slot, metadata) ... endRegister it for detection
Add your resource to the
inventories(orframeworks) table inshared/config.luawith the id you guarded on —['my-inventory'] = 'myinv'.
Your inventory must keep metadata on items — every photo, camera and album lives there. If writing the bridge is more than you want to take on, send us the name of the resource.
Languages#
41 languages ship in locales/: Arabic, Bengali, Bulgarian, Catalan, Chinese, Croatian, Czech, Danish, Dutch, English, Estonian, Finnish, French, German, Greek, Hebrew, Hindi, Hungarian, Indonesian, Italian, Japanese, Korean, Latvian, Lithuanian, Malay, Norwegian, Persian, Polish, Portuguese, Romanian, Russian, Slovak, Slovenian, Spanish, Swahili, Swedish, Thai, Turkish, Ukrainian, Urdu and Vietnamese.
Choose one in /cameraconfig → General → Language; it applies to every player at once, interface included. Any text missing from a language falls back to English. The language files are not encrypted, so any wording can be changed in its JSON file.



