Configuration
The data.json schema, per-vehicle sequence packs, admin settings, and player KVP overrides.
Where configuration lives
tAFK has three layers of configuration, resolved at playback time:
| Layer | Scope | Storage | Owner |
|---|---|---|---|
| Built-in defaults | All players | shared/schema.lua | Resource — restored if data.json is missing |
| Server state | All players, all vehicles | data.json at resource root | Admins via /tafk or direct JSON edit |
| Per-vehicle pack | One model | <otherResource>/tafk.json | Vehicle pack authors |
| Per-player overrides | One player | tLib KVP (tafk:* keys) | The player, via /tafk |
Merge order (lowest to highest priority): defaults → data.json → player KVP for settings; data.json union per-vehicle pack union (never conflicts — different scopes) for sequences.
data.json shape
Lives at tAFK/data.json. Created on first boot from shared/schema.lua defaults. Read once at server start. Editing data.json on disk requires a resource restart to take effect. Broadcast to clients via tafk:config_receive.
{
"version": 1,
"settings": {
"timeoutSeconds": 30,
"useMusic": true,
"musicVolume": 0.035,
"hideHudInAFK": true,
"beatAnchorMs": -15,
"minDurationMs": 5000,
"maxDurationMs": 10000
},
"sequences": [
{
"id": "seed_01",
"name": "Low Ground Wide Side Pan",
"enabled": true,
"vehicles": ["*"],
"start": {
"offset": [-6.0, -7.0, 0.1],
"rotation": [3.0, 0.0, 30.0],
"fov": 55.0,
"dof": { "near": 2.0, "far": 20.0, "strength": 0.7 }
},
"end": {
"offset": [-5.0, -6.5, 0.1],
"rotation": [3.0, 0.0, 28.0],
"fov": 55.0,
"dof": { "near": 2.0, "far": 20.0, "strength": 0.7 }
}
}
],
"vehicleConfigs": {
"bati801": {
"sequences": [
{ "id": "bati_low_pass", "name": "Low Pass", "vehicles": ["bati801"], "enabled": true, "start": {...}, "end": {...} }
]
}
}
}Music tracks aren't stored in data.json
Audio files are discovered automatically at server start by scanning the audio/ folder. See Music tracks below.
settings
| Key | Type | Default | Description |
|---|---|---|---|
timeoutSeconds | int | 30 | Idle seconds before auto-AFK fires. Zero disables auto-trigger |
useMusic | bool | true | Whether to start music on AFK enter |
musicVolume | float (0–1) | 0.035 | NUI audio element target volume |
hideHudInAFK | bool | true | Whether to hide HUD + minimap while AFK. When true, DisplayHud(false) / DisplayRadar(false) fire on AFK enter |
beatAnchorMs | int | -15 | Offset applied to next-beat timing. Negative = cut before beat (anticipation) |
minDurationMs | int | 5000 | Lower bound for sequence duration; beat-sync stays within range |
maxDurationMs | int | 10000 | Upper bound for sequence duration |
sequences[]
Each entry:
| Field | Type | Notes |
|---|---|---|
id | string | Stable identifier. Used for player opt-outs, admin edits. Generate once (seq_<timestamp> is fine) and never change |
name | string | Display name in /tafk menus |
enabled | bool | When false, skipped by the director |
vehicles | string[] | ["*"] = all vehicles. List specific model names (lowercase) to restrict. Match is case-insensitive |
start / end | object | See Keyframe shape |
Keyframe shape
{
"offset": [x, y, z],
"rotation": [pitch, roll, yaw],
"fov": 55.0,
"dof": { "near": 2.0, "far": 20.0, "strength": 0.7 }
}offset— vehicle-local coordinates (right = +x, forward = +y, up = +z). Metresrotation— degrees. Applied as delta to the implicit "point at vehicle" rotation at runtimefov— camera field of view in degrees (10–120)dof.near/.far— depth-of-field range in metresdof.strength— DOF intensity, 0 (no blur) to 1 (full)
Offsets also accept the alternate object form { "x": ..., "y": ..., "z": ... } — both shapes round-trip through tafkToVec3.
Music tracks
tAFK picks up audio files at server start. Supported extensions: .ogg, .mp3, .wav. There are two ways to get a file into the rotation:
Option 1 — name it one of the recognised patterns (zero config):
| Pattern | Range | Example |
|---|---|---|
bg<N> | 1–99 | bg1.ogg, bg6.ogg |
track<N> | 1–99 | track1.mp3 |
afk<N> | 1–99 | afk1.ogg |
music<N> | 1–99 | music1.ogg |
cinematic<N> | 1–99 | cinematic1.wav |
Option 2 — list any filename in audio/manifest.txt:
# One filename per line. Blank lines and #-comments are ignored.
intro.ogg
chill-beat.mp3
synthwave drive.wavBoth methods run at boot and results are merged (files listed in both places de-dupe). Delete a file from audio/ or remove its line from manifest.txt and restart to drop the track.
Why manifest.txt rather than a real directory listing?
FiveM's Lua runtime has no directory-enumeration API — the server can't ask "what's in audio/?" on its own. The pattern scan uses LoadResourceFile to probe 1,485 known names at startup (99 × 5 prefixes × 3 extensions), completes in milliseconds. manifest.txt fills the gap for any other name without you having to rename your files.
vehicleConfigs
Managed by tLib's Discovery module — do not edit this section directly in data.json. The admin editor writes to it via tafk:admin:upsertVehicleSequence, and external vehicle packs contribute via tafk_config metadata. See below.
Per-vehicle sequence packs
Vehicle resources can bundle their own AFK sequences. When the pack starts, tLib's Discovery module scans it for a tafk_config metadata key, loads the referenced JSON, and merges the keyed entries into the global vehicleConfigs map.
Pack layout
my-vehicle-pack/
├── fxmanifest.lua
├── stream/mycar.yft, .ytd, ...
└── tafk.jsonManifest declaration
fx_version 'cerulean'
game 'gta5'
files { 'tafk.json' }
tafk_config 'tafk.json'One metadata key per pack
tafk_config points at a single JSON file per resource. Multiple vehicles can live in the same file, keyed by model name.
JSON shape
{
"mycar": {
"sequences": [
{
"id": "mycar_front_pan",
"name": "Front Bumper Pan",
"enabled": true,
"vehicles": ["mycar"],
"start": {
"offset": [-0.8, 3.5, 0.4],
"rotation": [-2.0, 0.0, 175.0],
"fov": 42.0,
"dof": { "near": 0.5, "far": 4.0, "strength": 1.0 }
},
"end": {
"offset": [0.8, 3.5, 0.4],
"rotation": [-2.0, 0.0, 185.0],
"fov": 42.0,
"dof": { "near": 0.5, "far": 4.0, "strength": 1.0 }
}
}
]
},
"mysecondcar": {
"sequences": [ { ... } ]
}
}- Top-level keys are lowercase vehicle model names
- Each value has
{ "sequences": [...] }with entries in the same shape asdata.json.sequences[] vehiclesinside each entry should include the parent model for consistency but it's not enforced
Priority rules
When the same model name appears in multiple running resources, Discovery deduplicates: the first-scanned wins. Server-side admin edits through the tAFK UI write to data.json.vehicleConfigs and take priority over pack entries.
When configs refresh
- Server start — Discovery scans every running resource once
onResourceStart— when a pack starts after server boot, its configs merge in and clients get a fresh broadcast- Admin saves —
/tafkeditwith scope=vehicle writes and broadcasts immediately
Admin settings via /tafk
Every field in settings is tunable from /tafk when the player has the tlib.admin ACE. Changes apply live:
- Sliders fire
tafk:admin:updateSettingon every value change (coerced server-side to the correct type, clamped where needed) - Checkboxes fire on toggle
- Server persists with the read-merge-write pattern (preserves
vehicleConfigs) and broadcasts updated config to all clients
Slider change frequency
Dragging a slider fires one event per step. With the step sizes chosen (5 for timeout, 500 for ms durations, 5 for beat anchor), a full drag produces ~100 events. This is intentional for live preview and stays well within FiveM's event-rate limits.
Player KVP overrides
Backed by tLib's KVP module. Keys are prefixed tafk::
| Key | Type | Default | Sets when… |
|---|---|---|---|
tafk:playerDisabled | bool | not-set (→ enabled) | Player toggles AFK System off in /tafk |
tafk:music | bool | not-set (→ inherit) | Player toggles Music |
tafk:volume | float | not-set (→ inherit) | Player moves the Music Volume slider |
tafk:hudHide | bool | not-set (→ inherit) | Player toggles Hide HUD While AFK |
tafk:seqDisabled | string[] (JSON) | [] | Player unchecks a sequence in My Sequence Preferences |
tafkGetSettings() in cl_bridge.lua layers these on top of the server-distributed values. tafkGetSequences(model) filters by tafk:seqDisabled.
Reloading after manual edits
data.json is read once at resource start. If you edit the file directly, restart the resource (restart tAFK from console) to apply changes. Audio files in the audio/ folder are also re-scanned on restart.
Invalid sequences are dropped with a warning log and never reach clients.
