Skip to main content
Every option is documented inline in the config files. This page is the map of what lives where and which keys matter most.

Core keys

Config.Debug = true draws every sound point’s audible radius as a ring on the ground. It is by far the fastest way to work out why someone can’t hear anything.

Framework detection

Config.Framework = 'auto' probes in this order and takes the first resource that is running:
  1. qbx_coreqbx
  2. ox_coreox
  3. es_extendedesx
  4. qb-coreqb
  5. nothing → standalone
qbx_core is checked before qb-core because Qbox servers often ship a qb-core compatibility shim, and ox_core before es_extended for the same reason. Forcing a framework whose resource isn’t running logs a warning and falls back to standalone rather than erroring out. What actually changes per framework:
  • Jobs are read for job-gated booths and for admin jobs. Standalone always reports no job, so job rules never pass there.
  • Gangs are QBCore and Qbox only. On ESX, ox_core and standalone, gang rules never pass.
  • Identifiers work everywhere. On standalone the identifier is the player’s license:.
The panel re-fetches booths and permissions after a character switch or job change, so neither needs a reconnect.

Audio backend

Two engines can play the audio. Both are driven by the same authoritative server state — the queue, permissions, sync clock and every value below behave identically either way. Only the playback layer changes. Config.XSound tunes the xsound path:
spatial = true gives you real stereo positioning, but the falloff curve is xsound’s rather than the one set in Config.Audio.defaultFalloff. Set spatial = false if you want the three curves, multi-sound-point “loudest wins” and per-booth tuning to behave exactly as documented below — at the cost of stereo panning.
Beat-reactive lighting is real analysis only on the built-in engine with direct media. On the xsound backend there is no analyser signal at all, so the pulse is synthesised at beatBpm for every track. The lights still move; they aren’t following the music.
Switching backends needs a resource restart. Starting xsound while the server is already running is picked up automatically — anything currently playing is stopped first so the two engines never overlap.

Audio

Config.Audio sets the defaults every booth inherits unless it overrides them. Volume for a booth is recomputed continuously as the falloff curve against the loudest sound point you’re inside, multiplied by the DJ’s master volume, the booth’s ceiling, vehicle muffle, indoor boost and the listener’s own volume slider — then smoothed so it never pops.
Three faders stack: the DJ’s master volume, each listener’s personal slider, and the booth’s maxVolume ceiling. Any of them at zero is silence.

Effects

Config.Effects sets light and laser caps, draw distance, particle assets and beat reactivity. config/effects.lua holds Config.EffectDefaults and eight presets: classic club, rave, chill lounge, festival, strobe storm, smoke and lasers, blackout, and neon synth. Beat-reactive pulsing is real analysis for direct media. For YouTube it cannot be — the audio lives in a cross-origin frame that can’t be analysed — so the pulse is synthesised from a 120 BPM envelope. The lights still move, they just aren’t literally following the track.

Props

Config.BoothModels and Config.SpeakerModels each offer eight props to the in-game creator. Add your own model names to either list and they show up in the picker.
A model that isn’t streamed on the client simply won’t spawn. The booth interaction still works — you just get no visible prop.

Security limits

Config.Security holds the caps, URL policy, allow and deny lists, auto-ban toggle, logging and rate limits.
The Discord webhook URL is not in Config.Security. It is the server-only nexdev_djsystem_webhook convar — see Installation.
Hard caps enforced on the server regardless of what a client asks for: 100 tracks per queue, 25 playlists per player, 100 tracks per playlist, 100 database booths, 12 sound points and 24 effect emitters per booth, 12 lights and 16 lasers per rig, 120 m maximum audible distance, 3 hours maximum track duration.

Interface defaults

Config.UI sets the default accent colour, scale, anchor, blur and compact mode. Each player can override all of them from the settings tab, and their choice is persisted locally.

The usable item

Off by default. Turn on Config.Item.enabled and, with ox_inventory running, Config.Item.name (default dj_controller) becomes a usable item that opens the panel at the nearest booth the player is allowed to use. If ox_inventory isn’t started, the item is skipped with a console warning rather than erroring.
Config.Item.boothItem and Config.Item.consumeOnPlace are reserved keys. Nothing reads them in 1.0.0.

Locales

locales/en.json holds every string the script can display, as flat dotted keys. Config.Locale picks the file — 'fr' loads locales/fr.json. Only English ships.

Adding a translation

  1. Copy locales/en.json to locales/<language>.json.
  2. Translate the values. Leave the keys alone.
  3. Set Config.Locale to that name and restart.
English is always loaded as the base and your file is merged over the top, so a partial translation is fine — anything you haven’t translated falls back to English rather than showing a blank or a raw key. You can translate the strings players see most and leave the rest.
Set Config.Locale = 'auto' to use ox_lib’s language instead: the ox:locale convar on the server, and each player’s own ox_lib language setting on the client. That’s the only way to give different players different languages — Config.Locale is server-wide.
A missing, unreadable or malformed file logs one warning at startup and falls back to English. Every string also has a hard-coded English fallback in the code, so even a completely absent locales/ folder degrades labels and never breaks a feature.
Placeholders like %s carry values into the string — a track name, a count, a location. Keep them in your translation, in the same order.