Skip to content

Configuration

Every option of Cuxial Tablet: the sections of shared/config.lua, the catalogues in data/, what the admin panel edits and the hooks that connect your own resources.

shared/config.lua and the files in data/ hold the factory values. On the first start they are written to the database, and from then on almost everything is edited live from /tabletadmin. Only a few options are read from the file on every start.

After the first start, editing shared/config.lua or data/*.lua does not change what players see. Edit from the admin panel, or use Factory on a section of the panel to load the file's values again. The exceptions are the static options.

Static options ​

Read from shared/config.lua on every start and not shown in the panel.

OptionTypeDefaultWhat it does
debugbooleanfalsetrue prints queries and events to the console. The cuxial_tablet_debug convar set to 1 does the same.
ui.accentstring (hex)configurableAccent colour of the interface.
ui.soundsbooleantruetrue plays interface sounds on actions.
commands.adminstring'tabletadmin'Command that opens the admin panel, without the slash.
admin.permissionstring'admin'Permission required for the panel, the operations and the moderation of news, streams and the gallery. See Permissions.

The name shown in the header of the tablet comes from the UI_SHELL_BRAND, UI_SHELL_BRAND_A and UI_SHELL_BRAND_B keys of locales/en.json and locales/es.json.

Tablet · tablet ​

OptionTypeDefaultWhat it does
enabledbooleantruefalse stops everyone from opening the tablet. The admin panel keeps working.
keybindstring'F1'Default key. Changing it requires players to reconnect; each player can remap it in the GTA key settings. Mouse buttons are accepted as MOUSE_BUTTON.
startPagestring'player'Page shown on opening: player, news, jobsOnline, jobsCity, crosshair or vip.
rememberPagebooleantruetrue reopens on the last page visited.
prop.modelstring'prop_cs_tablet'Prop held in the hand.
prop.bonenumber60309Bone it is attached to. 60309 is the left hand.
prop.offsettable{ x = 0.0, y = 0.0, z = 0.03 }Offset from the bone.
prop.rotationtable{ x = 10.0, y = 160.0, z = 0.0 }Rotation of the prop.
anim.dict, anim.clipstringtablet animationAnimation played while the tablet is open.
anim.flagnumber50Animation flag. 50 is upper body and loop.
canOpen.deadbooleanfalsetrue allows opening while dead or injured.
canOpen.swimmingbooleanfalsetrue allows opening while swimming.
canOpen.drivingbooleanfalsetrue allows opening as the driver.
canOpen.passengerbooleantruetrue allows opening as a passenger.
canOpen.cuffedbooleanfalsetrue allows opening while cuffed.
pages.player, pages.news, pages.jobsOnline, pages.jobsCity, pages.crosshair, pages.vipbooleantruefalse removes that page from the tablet.

VIP · vip ​

OptionTypeDefaultWhat it does
accountstring'coins'Money account of the framework that holds the coins. It must exist. See Installation.
cooldownMsnumber2000Milliseconds a player must wait between two purchases.
stockModestring'perItem''perItem' keeps a global stock per item and discounts each sale. 'none' ignores stock.
newDaysnumber7Days an item shows the new label after entering the catalogue.
topSellersCountnumber5Items marked top sellers, by sales of the last 30 days.
cart.maxItemsnumber10Maximum lines in the cart.
gift.enabledbooleantruetrue allows gifting items to online players.
gift.feePctnumber0Percent added to the price when gifting.
gift.messageMaxLennumber120Maximum length of the gift message.
wallet.transfer.enabledbooleantruetrue allows coin transfers between players.
wallet.transfer.feePctnumber5Percent lost as a fee on each transfer.
wallet.transfer.minnumber10Minimum coins per transfer.
wallet.transfer.maxPerDaynumber5000Coins a player can send per day. 0 removes the cap.
wallet.historyLimitnumber50Movements shown in the wallet.
codes.prefixstring'VIP'Prefix of redeemable codes, as in VIP-XXXX-XXXX. Up to 12 characters.
codes.redeemPerHournumber10Redeem attempts per hour and player.
loyalty.enabledbooleantruetrue turns on the loyalty tiers.
loyalty.tierstable[]four tiersTiers ordered by spent, see below.

Each loyalty tier:

FieldTypeWhat it does
idstringInternal name.
labelstringName shown to the player.
spentnumberCoins spent needed to reach the tier. The first tier is 0.
discountPctnumberDiscount on shop prices.
extraDailyDaybooleantrue adds an extra day at the end of each daily cycle.
accentstring (hex)Colour of the tier.

The default tiers are Bronze (0 coins, no discount), Silver (2,500 coins, 3 %), Gold (10,000 coins, 6 %, extra day) and Diamond (30,000 coins, 10 %, extra day).

Daily reward · daily ​

OptionTypeDefaultWhat it does
enabledbooleantruefalse hides the daily tab.
cycleDaysnumber7Days in the cycle. Must match the days in data/daily.lua.
claimWindowHoursnumber24Hours between two claims.
breakStreakOnMissbooleantruetrue restarts the streak at 1 when a player claims after more than graceHours without claiming. false never breaks it.
graceHoursnumber48Hours without claiming before the streak is at risk. Never less than claimWindowHours.
streakBonusPctnumber5Percent of extra coins per streak day, on coin rewards only.
streakBonusMaxPctnumber50Cap of the streak bonus.
rescue.enabledbooleantruetrue lets a player pay to keep a streak at risk.
rescue.pricenumber150Coins per rescue.
rescue.maxPerCyclenumber1Rescues allowed per cycle.

Season pass · pass ​

OptionTypeDefaultWhat it does
enabledbooleantruefalse hides the pass tab and stops XP.
season.namestring'SEASON 1'Name shown.
season.numbernumber1Season number. Changing the name or the number starts a new season for everyone.
season.endsAtnumber0Unix time, in seconds, of the end of the season shown in the pass. 0 shows no date.
totalTiersnumber15Levels. Must match the levels in data/pass.lua.
xpPerLevelnumber1000XP per level.
premiumPricenumber3000Coins to activate premium for the season.
xpSources.dailynumber100XP per daily claim.
xpSources.shopPerCoinnumber1XP per coin spent in the shop or on cases.
xpSources.jobCompletenumber150XP per completed job. See EmitJobCompleted.
xpSources.playtimePerMinnumber2XP per minute online. 0 turns it off.
missions.weeklyCountnumber3Missions active each week, picked from data/missions.lua.
missions.resetDaynumber1Day the week resets: 1 Monday to 7 Sunday.

Cases · cases ​

OptionTypeDefaultWhat it does
enabledbooleantruefalse hides the cases tab.
showOddsbooleantruetrue shows the odds per rarity on each tier.
multiOpennumber[]{ 1, 3, 5 }Amounts a player can open at once.
stripLengthnumber40Cards in the roulette strip.
winnerIndexnumber32Position of the winning card in the strip. At most stripLength.
pity.enabledbooleantruetrue guarantees a legendary after a number of openings without one.
pity.legendaryAfternumber50Openings without a legendary before one is forced.

News · news ​

OptionTypeDefaultWhat it does
enabledbooleantruefalse turns the news off; the page shows nothing and nobody can publish.
trendingCountnumber3Entries shown as trending.
autoTrendingLikeThresholdnumber500Likes from which an entry becomes trending.
publisherJobsstring[]{ 'journalist', 'reporter' }Jobs that can publish. Staff always can.
allowAnonLikesbooleanfalsetrue accepts likes from players without a loaded character.
pageSizenumber20Entries per page of the feed.
categoriesstring[]seven categoriesCategories offered when writing. Categories already used by saved entries are added to the list.

Live streams · live ​

OptionTypeDefaultWhat it does
enabledbooleantruefalse turns live streams off.
broadcasterJobsstring[]{ 'journalist', 'reporter', 'police' }Jobs that can go live. Staff always can.
maxDurationSecnumber14400Maximum length of a stream, in seconds.
maxViewersnumber50Viewers per stream.
enc.width, enc.bitrate, enc.fpsnumber960, 1500000, 20Video profile used when the relay is configured.
chat.enabledbooleantruetrue enables the chat of the stream.
chat.maxLennumber140Maximum length of a chat message.
chat.perMinutenumber20Messages per minute and viewer.
camera.propstring'prop_v_cam_01'Camera prop held by the broadcaster.
camera.bonenumber28422Bone it is attached to. 28422 is the right hand.
camera.offset, camera.rotationtablesee filePosition and rotation of the prop.
camera.animDict, camera.animClip, camera.animFlagstring, string, numbershoulder camera animationAnimation played while broadcasting.
camera.lensForwardnumber0.30Metres in front of the prop where the stream camera sits.
camera.zoomMin, camera.zoomMaxnumber20.0, 60.0Field of view range of the zoom.
camera.stopKeystring'BACK'Default key that stops the stream. Changing it requires players to reconnect.

Crosshair · crosshair ​

OptionTypeDefaultWhat it does
enabledbooleantruefalse turns the whole feature off.
hideNativebooleantruetrue hides the game's reticle while the custom crosshair is on.
allowHitmarkerbooleantruefalse removes the hitmarker and the damage numbers for everyone.
allowDamageNumbersbooleantruefalse removes the damage numbers for everyone. Needs allowHitmarker.
tickMsnumber50Milliseconds between updates of the crosshair state.
maxLayersnumber6Layers per crosshair.
maxSizenumber64Maximum size of a layer, in pixels at 1080p.
gallery.enabledbooleantruetrue enables the community gallery.
gallery.maxPerPlayernumber5Entries a player can publish.
gallery.nameMaxLennumber24Maximum length of an entry name.
gallery.pageSizenumber30Entries per page.
defaults.enabledbooleanfalsetrue turns the custom crosshair on for players who have not set anything.
defaults.presetstring'classic_cross'Starting preset, by id from data/crosshair_presets.lua.
defaults.colorstring (hex)'#ffffff'Starting colour.
defaults.alwaysShowbooleanfalsetrue draws it without aiming.
defaults.dynamictable{ enabled = true, moveGap = 4, sprintGap = 8, vehicleGap = 6, aimGap = -2, smooth = 0.2 }Starting dynamic spread: extra gap while moving, sprinting and driving, reduction while aiming, and smoothing.
defaults.perWeapon.enabledbooleanfalsetrue starts with one profile per weapon group.
hitmarkerDefaults.enabledbooleantrueHitmarker on for players who have not set anything.
hitmarkerDefaults.stylestring'cross'cross, x, ring or dot.
hitmarkerDefaults.soundbooleantruetrue plays a tick on hit.
hitmarkerDefaults.volumenumber0.35Volume of the tick, 0 to 1.
hitmarkerDefaults.showDamagebooleantruetrue shows the damage number.
hitmarkerDefaults.durationMsnumber220Duration of the marker, 100 to 600.
weaponGroupsstring[]eight groupsWeapon groups offered for per-weapon profiles: melee, pistol, smg, rifle, shotgun, sniper, heavy, throwable.

data/crosshair_presets.lua holds the 146 presets and the defaults of each layer kind. It is read from the file on every start and is not edited from the panel.

Jobs · jobs ​

OptionTypeDefaultWhat it does
onlineRefreshSecnumber5Seconds the on-duty counts are cached.
city.startModestring'waypoint''waypoint' marks the job's coordinates on the map. 'event' fires a client event with the job id.
city.startEventstring''Client event fired when startMode = 'event' and the job has no event of its own.

Catalogues · data/ ​

The files in data/ are the factory catalogues. They are delivered with sample rows that reference common inventory items; replace them with your own from the admin panel. Every row has the fields below.

Shop · data/shop.lua ​

FieldWhat it does
idUnique and stable. Never reuse an id: stock and history point to it.
enabledfalse hides the item.
itemKeyItem name in the inventory.
name, descriptionShown on the card.
categoryOne of the categories listed at the end of the file (shopCategories).
raritycommon, rare, epic or legendary.
priceCoins.
amountUnits of the main item.
stockUnits for sale with stockMode = 'perItem'. -1 is unlimited.
imageFull URL or path inside the inventory's images folder. Empty uses the inventory's image of itemKey.
bundleExtra items delivered with the main one: { itemKey, amount, label, metadata }.
metadataMetadata of the main item.
featuredtrue shows it in the featured sort.
discount.pct, discount.untilAtFlash offer: percent and Unix time of its end. 0 is no offer.
limited.untilAtUnix time after which the item leaves the shop. 0 is permanent.
requires.loyaltyTierLoyalty tier id required to buy. Empty is none.
addedAtUnix time the item entered the catalogue, for the new label. The panel fills it.
sortManual order, lowest first.
themeTheme of the card. Empty or one of shopThemes.
preview3dtrue shows the View in 3D button.
previewModelModel shown in 3D. Empty uses itemKey as a weapon model.

Daily · data/daily.lua ​

One row per day of the cycle: day, enabled, kind (item, coins or cash), itemKey, amount, label, milestone and metadata.

Pass · data/pass.lua ​

One row per level: level, free and premium. Each reward has kind (item, coins, cash or none), itemKey, amount, label, milestone and metadata.

Cases · data/cases.lua ​

  • tiers: id, enabled, label, accent, price, image (empty uses images/cases/<id>.webp from the interface) and weights, the probability of common, rare, epic and legendary, adding up to 1.
  • pool: the drops, shared by every tier: id, enabled, kind, itemKey, name, rarity, amount, image and metadata.

Missions · data/missions.lua ​

id, enabled, label, type, target, xp and icon. The type decides what target counts:

TypeTarget
jobsCompleted jobs
playtimeMinutes online
dailyDaily claims
shopCoins spent
distanceMetres travelled
casesCases opened

Jobs online · data/jobs_online.lua ​

id, enabled, job (job name in the framework), name, image, description, category, color and priority (highest first).

City jobs · data/jobs_city.lua ​

id, enabled, name, image, description, coords and event (client event for this job when startMode = 'event'; empty uses jobs.city.startEvent). Coordinates can be picked in the world from the admin panel.

Images of jobs and cases are paths inside the web/dist folder of the resource, such as images/cityjobs/trucker.webp.

Hooks ​

The folder hooks/ holds Lua adapters that connect the tablet to your own resources. Edit them freely; keep the function names and the shape of what they return.

FileFunctionReturnsOut of the box
hooks/server/vehicles.luaGetVehicles(src){ name, model, plate, class?, status }[] with status one of garage, out, destroyed, impoundReads qbx_vehicles
hooks/server/properties.luaGetProperties(src){ name, address, type }[] with type one of house, apartment, garage, businessReads nolag_properties
hooks/server/playtime.luaGetWorkedHours(citizenid), GetSessionMinutes(src)Whole hours, minutesHours from the player_jobs_activity table when it exists; session minutes counted by the tablet
hooks/server/stats.lua, hooks/client/stats.luaGetStats(src), GetStats(){ label, value, max?, icon? }[] extra stats for the profileEmpty
hooks/server/xp.luaOnJobCompleted(cb), EmitJobCompleted(src, info)—Listens to cuxial_jobs:server:JobCompleted
hooks/server/images.luaGetItemImage(itemKey), GetItemLabel(itemKey)Image URL and label of an inventory itemDetects ox_inventory or qb-inventory

When a source resource is not running, the adapter returns an empty list and the tablet works the same.

hooks/server/vehicles.lua
lua
function Hooks.GetVehicles(src)
    local player = CuxialTablet.getPlayer(src)
    if not player then return {} end
    local rows = MySQL.query.await('SELECT plate, vehicle FROM my_vehicles WHERE owner = ?', { player.citizenid })
    local out = {}
    for i, v in ipairs(rows or {}) do
        out[i] = { name = v.vehicle, model = v.vehicle, plate = v.plate, status = 'garage' }
    end
    return out
end

Common changes ​

Use an existing money account for the coins

From the admin panel, section VIP, set account to bank. Or, before the first start:

shared/config.lua
lua
vip = {
    account = 'bank',
    ...
},

Start city jobs from your own job resource

Section Jobs of the panel: city.startMode = event and city.startEvent = myjobs:client:start. The event receives the job id.

lua
RegisterNetEvent('myjobs:client:start', function(jobId)
    -- start the job
end)

Turn off the VIP economy and keep the rest

Section Tablet of the panel: pages.vip = false. The page disappears and no coins are needed.

Change the tablet key

Section Tablet of the panel: keybind = F2. Players who had already joined keep their binding and can change it in the GTA key settings.

© Cuxial