> For the complete documentation index, see [llms.txt](https://5scripts-1.gitbook.io/docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://5scripts-1.gitbook.io/docs/assets/5s_racing/config.md).

# Config

The configuration is split across two files:

* `config/shared/config_shared.lua` - the bulk of the gameplay settings (shared between client and server).
* `config/server/config_server.lua` - server-only settings (identifiers, Discord webhooks).

Both files live in the `escrow_ignore` list, so they are fully open and safe to edit.

## config/shared/config\_shared.lua

```lua
ConfigShared = {

    -- Player defaults (until they set their own)
    defaultPreferences = {
        checkpointColor   = "#907f99", -- Checkpoint colour.
        minimapRouteColor = "#c0b3ef", -- Minimap route colour.
        unitSystem        = "metric",  -- "metric" (km/h) or "imperial" (mph).
        leaderboardPlacement = "topRight", -- "topRight" (panel) or "bottomRight" (pills).
    },

    -- Track creation
    priceToCreateTrack   = 300, -- Cost to create a track. 0 = free.
    maxTracksPerPlayer   = 3,   -- Max tracks per player (verified don't count; admins unlimited).
    vehicleReturnTime    = 10,  -- Seconds to get back in your car before the race quits you.
    startRaceMaxDistance = 100, -- Confirm if host is this far (m) from the start. 0 = off.

    -- ELO ranking (skill rating; maths in server/editable/elo.lua)
    elo = {
        enabled  = true,
        startElo = 1000, -- Starting rating for new players.
        minElo   = 0,    -- Rating floor.
        kFactor  = 20,   -- Swing size (max ~kFactor/2 per race). Higher = bigger swings.
        topPercentage = 0.25,   -- Top share of finishers that gain rating; rest only lose.
        referenceLength = 1000, -- Track length (m) that swings at 1x.
        minLengthMultiplier = 0.5, -- Length-multiplier floor (short tracks).
        maxLengthMultiplier = 1.5, -- Length-multiplier cap (long tracks).
    },

    -- Vehicle classes (scoring in client/editable/performanceClass.lua)
    vehicleClasses = {
        -- Force a model into a class: ["tailgater2"] = "S".
    },
    -- Classes allowed to race. D-X = performance tiers; MT/OF/VN/BK = bike/off-road/van/bicycle.
    availableVehicleClasses = {
        "D", "C", "B", "A", "S", "S+", "X",
        "MT", "OF", "VN", "BK"
    },

    -- Race types & settings
    disabledRaceTypes = {
        -- Race types players can't pick, e.g. "Drift".
    },
    disabledSettings = {
        -- Race options players can't change when creating a race.
    },
    verifiedTracksOnly = false, -- Only admin-verified tracks can be raced.

    -- Leaderboards & personal bests
    maxLeaderboardEntries = 50, -- Entries kept per track ranking.
    splitRecordScope = "class", -- Best times: "class" (per car class) or "global" (per track).

    -- Drift scoring (defaults work well)
    drift = {
        scoreRate    = 140.0,     -- How fast points build while drifting.
        scoreCeiling = 100000000, -- Anti-cheat cap on a race's score.
        minSpeed     = 6.0,       -- Min speed (m/s) for a drift to count.
        minAngle     = 12.0,      -- Below this angle (deg) it isn't a drift.
        maxAngle     = 90.0,      -- At/above this angle the drift scores its max.
        spinoutAngle = 110.0,     -- Past this angle = spun out (no points).
    },

    -- Proximity join (walk up + press a key to join)
    proximityJoin = {
        enabled      = true,
        key          = 38,   -- Join key (38 = E).
        distance     = 6.0,  -- How close (m) to join.
        viewDistance = 35.0, -- Range (m) the prompt shows.
    },

    -- Automated races (server hosts public races on a timer)
    automatedRaces = {
        enabled   = false,
        trackPool = "verified", -- IDs { 1, 4, 7 }, or "verified", or "public".
        raceType  = "sprint",   -- Race type (drag tracks stay drag).
        intervalMinutes   = 60,  -- Minutes between races.
        joinWindowSeconds = 300, -- Time to join before start.
        minPlayers        = 2,   -- Needed to start, else cancelled (refunded).
        settings = {             -- Settings used for every automated race.
            laps              = 2,
            ghostMode         = true,
            ghostModeDuration = 0,
            enterPrice        = 0,
            useRacerLimit     = false,
            racerLimit        = 999,
        },
    },

    -- Anti-cheat & limits (safe to leave as-is)
    antiCheat = {
        createTrackCooldown = 5000, -- Wait (ms) between track creates. 0 = off.
        createRaceCooldown  = 5000, -- Wait (ms) between race creates. 0 = off.
        inviteCooldown      = 1500, -- Wait (ms) between invites. 0 = off.
        inviteMaxDistance   = 30.0, -- Target must be within this (m) to invite. 0 = off.

        maxCheckpoints = 384,  -- Max checkpoints per track.
        maxObjects     = 4096, -- Max props per track.
        maxPeds        = 4096, -- Max peds per track.
        maxParticles   = 512,  -- Max particles per track (preset decorations excluded).

        maxTrackNameLength        = 64,  -- Track name character limit.
        maxTrackDescriptionLength = 256, -- Track description character limit.

        checkpointMaxDistance = 100.0, -- Racer must be within this (m) of a checkpoint. 0 = off.
        minCheckpointDistance = 10.0,  -- Min gap (m) between checkpoints. 0 = off.
    },

    -- Checkpoint decoration presets (props dressed onto checkpoints; schema explained below)
    checkpointPresets = {
        { key = 'none',  label = 'Plain', marker = true, decorations = {} },
        { key = 'tyres', label = 'Tyres', marker = false, image = 'https://cfx-nui-5s_racing/images/tyres.webp', decorations = {
            { model = 'prop_offroad_tyres02', side = -1, offset = 0.8, collision = true, rot = { x = 0.0, y = 0.0, z = 0.0 } },
            { model = 'prop_offroad_tyres02', side =  1, offset = 0.8, collision = true, rot = { x = 0.0, y = 0.0, z = 0.0 } },
        }},
        { key = 'tyresGhost', label = 'Tyres (pass-through)', marker = false, image = 'https://cfx-nui-5s_racing/images/tyres_ghost.webp', decorations = {
            { model = 'prop_offroad_tyres02', side = -1, offset = 0.8, collision = false, rot = { x = 0.0, y = 0.0, z = 0.0 } },
            { model = 'prop_offroad_tyres02', side =  1, offset = 0.8, collision = false, rot = { x = 0.0, y = 0.0, z = 0.0 } },
        }},
        { key = 'tyresFlares', label = 'Tyres + flares', marker = false, image = 'https://cfx-nui-5s_racing/images/tyres_flares.webp', decorations = {
            { model = 'prop_offroad_tyres02', side = -1, offset = 0.8, collision = false, rot = { x = 0.0, y = 0.0, z = 0.0 },
              particle = { dict = 'core', name = 'exp_grd_flare', scale = 1.0, z = 0.5, rot = { x = 0.0, y = 0.0, z = 0.0 } } },
            { model = 'prop_offroad_tyres02', side =  1, offset = 0.8, collision = false, rot = { x = 0.0, y = 0.0, z = 0.0 },
              particle = { dict = 'core', name = 'exp_grd_flare', scale = 1.0, z = 0.5, rot = { x = 0.0, y = 0.0, z = 0.0 } } },
        }},

        { key = 'golfFlags',   label = 'Golf flags',      marker = false, image = 'https://cfx-nui-5s_racing/images/prop_golfflag.webp', decorations = {
            { model = 'prop_golfflag', side = -1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = 90.0 } },
            { model = 'prop_golfflag', side =  1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = 90.0 } },
        }},
        { key = 'beachFlags',  label = 'Beach flags',     marker = false, image = 'https://cfx-nui-5s_racing/images/prop_beachflag_le.webp', decorations = {
            { model = 'prop_beachflag_le', side = -1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = -135.0 } },
            { model = 'prop_beachflag_le', side =  1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = -135.0 } },
        }},
        { key = 'beachFlagsA', label = 'Beach flags (A)', marker = false, image = 'https://cfx-nui-5s_racing/images/prop_beachflag_01.webp', decorations = {
            { model = 'prop_beachflag_01', side = -1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = -135.0 } },
            { model = 'prop_beachflag_01', side =  1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = -135.0 } },
        }},
        { key = 'beachFlagsB', label = 'Beach flags (B)', marker = false, image = 'https://cfx-nui-5s_racing/images/prop_beachflag_02.webp', decorations = {
            { model = 'prop_beachflag_02', side = -1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = -135.0 } },
            { model = 'prop_beachflag_02', side =  1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = -135.0 } },
        }},
        { key = 'tyreWall',    label = 'Tyre wall',       marker = false, image = 'https://cfx-nui-5s_racing/images/prop_tyre_wall_01.webp', decorations = {
            { model = 'prop_tyre_wall_01', side = -1, offset = 1.0, collision = true, rot = { x = 0.0, y = 0.0, z = 90.0 } },
            { model = 'prop_tyre_wall_01', side =  1, offset = 1.0, collision = true, rot = { x = 0.0, y = 0.0, z = 90.0 } },
        }},
        { key = 'cones',       label = 'Cones',           marker = false, image = 'https://cfx-nui-5s_racing/images/prop_roadcone02a.webp', decorations = {
            { model = 'prop_roadcone02a', side = -1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = 0.0 } },
            { model = 'prop_roadcone02a', side =  1, offset = 0.95, collision = false, rot = { x = 0.0, y = 0.0, z = 0.0 } },
        }},
    },
    -- Preset a new quick checkpoint (U) starts with. Must be a key above.
    defaultCheckpointPreset = 'tyresFlares',

    -- Glow around decoration props. One shared colour for all (engine limit).
    checkpointDecorationOutline = {
        enabled = true,
        color   = { r = 255, g = 255, b = 255, a = 255 }, -- 0-255 per channel.
    },
    -- Snap race-spawned decorations to the ground (fixes floating/sunk tyres). Preview unaffected.
    checkpointDecorationSnapToGround = true,

    -- How forgiving checkpoint detection is: a checkpoint counts when the car is within radius * this.
    checkpointHitRadiusMultiplier = 1.5,

    -- Object library (prop picker in the creator)
    editorObjects = {
        custom = {
            -- Add your own: { model = 'prop_my_ramp', image = 'https://your.cdn/ramp.png' }.
        },
        removed = {
            -- Hide props by model name: 'prop_something_you_dont_want'.
        },
        -- Side-menu groups. A prop joins the first group whose keyword is in its name; rest = "Other".
        categories = {
            -- { key = 'track', keywords = { 'cone', 'arrow', 'ramp', 'tyre', ... } },
        },
    },

    abandonCommand = "abandonrace", -- Command to leave a race.

    -- Display & HUD
    leaderboardTopRightYOffset = 0, -- Push the top-right leaderboard down if it overlaps your HUD (px).
    dragCountdownLength = 10,        -- Drag countdown start (normal races count from 3).
    checkpointDrawType  = "dui",     -- "dui" (nicer) or "3dtext" (lighter on performance).
    disableRacesNotifications = false, -- Hide the public-race "starting" notification.
    disableRacesBlips         = false, -- Hide the public-race map blip.

    -- Payments & prize pool
    paymentMethod = "money", -- Entry money source: "money", "bank", or "both".
    rewards = {
        enabled = true,                   -- ON = fees form a prize pot. OFF = fees taken, no payout.
        distribution = { 0.6, 0.3, 0.1 }, -- Pot share per place. { 1.0 } = winner takes all. Sum <= 1.
        houseCut  = 0.0,     -- Server's cut of the pot, 0-1.
        account   = "money", -- Winnings paid to "money" or "bank".
        minRacers = 2,       -- Racers needed for payout.
        refundBelowMinimum = true, -- Refund fees if too few racers.
    },
    priceLimits = { -- Entry fee range a host can set.
        min = 0,
        max = 5000,
    },

    -- Weather options players can choose for a race
    availableWeathers = {
        "EXTRASUNNY", "RAIN", "CLEARING", "THUNDER", "SMOG", "HALLOWEEN", "XMAS"
    },

    -- Banned words for track names, descriptions and nicknames
    blockedKeyWords = {

    }
}
```

## config/server/config\_server.lua

```lua
ConfigServer = {
    DefaultNicknamePrefix = "Driver ", -- Auto nickname start, e.g. "Driver 1234".
    UsedIdentifier = 'license',        -- Save players by: 'steam', 'license', 'license2', 'discord'...

    -- Discord webhooks (blank URL = that event is skipped)
    webhooks = {
        enabled = false, -- Master switch.

        raceFinished = { webhook = '', title = 'Race finished', color = 0x5865F2 }, -- Standings + ELO + payouts.
        raceCreated  = { webhook = '', title = 'Race created',  color = 0x57F287 }, -- New race hosted.
        trackCreated = { webhook = '', title = 'Track created',  color = 0xFEE75C }, -- New track saved.
        trackDeleted = { webhook = '', title = 'Track deleted',  color = 0xED4245 }, -- Track deleted.
    },
}
```

***

## Options reference

A deeper explanation of the options whose behaviour isn't obvious from the inline comments.

### Player defaults (`defaultPreferences`)

Applied to a player until they set their own preferences in the tablet.

* `checkpointColor` / `minimapRouteColor` - hex colours for checkpoints and the minimap route line.
* `unitSystem` - `"metric"` (km/h) or `"imperial"` (mph).
* `leaderboardPlacement` - in-race leaderboard spot: `"topRight"` (big panel) or `"bottomRight"` (small pills).

### Track creation

* `priceToCreateTrack` - cost for a player to create a track. `0` = free.
* `maxTracksPerPlayer` - how many tracks one player can own at once. Verified tracks don't count toward the limit; admins are unlimited.
* `vehicleReturnTime` - seconds a player has to get back in their car after leaving it before the race quits them.
* `startRaceMaxDistance` - if the host is this many metres or more from the start line, they're asked to confirm before starting. `0` = off.

### ELO ranking (`elo`)

A skill rating that goes up when you beat better players and down when you lose. The everyday knobs are here; the algorithm itself is in `server/editable/elo.lua`.

* `enabled` - master switch for ranked/ELO.
* `startElo` - rating every new player starts at.
* `minElo` - rating can never fall below this.
* `kFactor` - how big rating changes are. The most a player can swing in one race (at the reference length, evenly matched) is about `kFactor / 2` - so `20` ≈ ±10 max. Higher = bigger swings.
* `topPercentage` - top share of finishers that gain rating (`0.25` = top 25%). Everyone below only loses rating.
* `referenceLength` - track length (m) where swings are "normal". Longer tracks swing more, shorter ones less.
* `minLengthMultiplier` / `maxLengthMultiplier` - clamp on the length multiplier (`routeLength / referenceLength`) so a very long track can't balloon the swing and a tiny one isn't pointless. With a 1000 m reference: a 1 km track scores at 1.0×; anything shorter caps at 0.5×; a 5 km track caps at 1.5× instead of 5×.

### Vehicle classes

Cars are rated D up to X by performance, plus a few native classes - see `client/editable/performanceClass.lua` for the scoring.

* `vehicleClasses` - force a specific car model into a class, e.g. `["tailgater2"] = "S"`.
* `availableVehicleClasses` - which classes are allowed to race. Remove one to ban it.
  * `D, C, B, A, S, S+, X` - performance tiers worked out from the car's stats.
  * `MT, OF, VN, BK` - taken straight from the vehicle's in-game class: MT = motorcycles, OF = off-road, VN = vans, BK = bikes (bicycles).

### Race types & settings

* `disabledRaceTypes` - race types players can't pick, e.g. `"Drift"`. Selectable types are **Sprint**, **Drift** and **Elimination**; **Drag** is locked to drag tracks.
* `disabledSettings` - race options players can't change when creating a race.
* `verifiedTracksOnly` - if true, only admin-verified tracks can be raced. Players can still build and share their own.

### Leaderboards & personal bests

* `maxLeaderboardEntries` - how many entries each track's ranking keeps (best times or drift scores).
* `splitRecordScope` - best-time records: `"class"` = one per car class (fairer) or `"global"` = one per track.

### Drift scoring (`drift`)

Defaults work well; change only if needed.

* `scoreRate` - how fast points build up while drifting (higher = faster).
* `scoreCeiling` - safety cap on a single race's score (anti-cheat).
* `minSpeed` - minimum speed (m/s) for a drift to count.
* `minAngle` - below this angle (degrees) it isn't a drift.
* `maxAngle` - at/above this angle the drift scores at its max.
* `spinoutAngle` - past this angle the car counts as spun out (no points).

### Proximity join (`proximityJoin`)

Walk up to a race and press a key to join.

* `enabled` - on/off.
* `key` - key to join (`38` = E).
* `distance` - how close (m) you must be to join.
* `viewDistance` - how far away (m) the "press to join" prompt shows.

### Automated races (`automatedRaces`)

The server hosts public races on its own, on a timer - no player host needed.

* `enabled` - on/off.
* `trackPool` - which tracks to use: a list of IDs like `{ 1, 4, 7 }`, or `"verified"`, or `"public"`.
* `raceType` - race type to run (drag tracks always stay drag).
* `intervalMinutes` - minutes between automated races.
* `joinWindowSeconds` - how long players have to join before it starts.
* `minPlayers` - needed to start, or it's cancelled and buy-ins refunded.
* `settings` - the race settings used for every automated race (`laps`, `ghostMode`, `ghostModeDuration`, `enterPrice`, `useRacerLimit`, `racerLimit`).

### Anti-cheat & limits (`antiCheat`)

Server guards against spam/abuse. Safe to leave as-is.

* `createTrackCooldown` / `createRaceCooldown` - wait (ms) between a player creating tracks / races. `0` = off.
* `inviteCooldown` - wait (ms) between a player sending invites. Kept short so inviting a full grid isn't tedious. `0` = off.
* `inviteMaxDistance` - a target must be within this many metres of the host to be invited. You invite by player ID, so this stops inviting people across the map. `0` = off.
* `maxCheckpoints` / `maxObjects` / `maxPeds` - most checkpoints / props / peds a track can have.
* `maxParticles` - most particle effects a track can place. Checkpoint preset decorations aren't counted here - they're stored on the checkpoint and spawned on the fly during the race.
* `maxTrackNameLength` / `maxTrackDescriptionLength` - character limits.
* `checkpointMaxDistance` - a racer must be within this many metres of a checkpoint for it to count. `0` = off.
* `minCheckpointDistance` - checkpoints must be at least this far (m) apart so they can't be stacked. `0` = off.

### Checkpoint decoration presets (`checkpointPresets`)

Pre-dressed checkpoints with props on each side (tyres, flares, flags...). The props stick to the checkpoint in the creator (move/resize it and they follow) and are saved into the track.

Per preset:

* `key` - id.
* `label` - name shown in the picker.
* `image` - optional picture URL for the picker tile.
* `marker` - whether the checkpoint still draws its floor ring. `true` (default) keeps it; decorated presets set `false` so the props mark the gate on their own.
* `decorations` - the props.

Each decoration:

* `model` - the prop to place.
* `side` - `-1` = left, `+1` = right.
* `offset` - how far out it sits (share of the checkpoint radius; `1.0` = edge, lower = inward).
* `z` - raise/lower the prop.
* `rot` - turn the prop, `{ x, y, z }` in degrees.
* `collision` - `true` (default) = solid prop cars bounce off; `false` = pass-through marker.
* `particle` - optional effect on the prop: `{ dict, name, scale, z = height, rot }`.

Built-in presets: `none` (plain), `tyres` (solid tyre walls), `tyresGhost` (pass-through tyres), `tyresFlares` (tyres + flare particles), `golfFlags`, `beachFlags`, `beachFlagsA`, `beachFlagsB`, `tyreWall`, `cones`. Every preset except `none` hides the floor ring.

Related options:

* `defaultCheckpointPreset` - preset a freshly placed quick checkpoint (U) starts with. Must be a `key` from `checkpointPresets`.
* `checkpointDecorationOutline` - the thin glow drawn around every decoration prop (creator preview and race). `enabled` toggles all at once. The game renders every visible outline in ONE shared colour, so `color` is global (`{ r, g, b, a }`, 0-255 each).
* `checkpointDecorationSnapToGround` - rest decoration props on the real ground when they spawn during a race (fixes floating/sunk tyres on imported tracks). The creator preview is left alone so you can author exact positions there.
* `checkpointHitRadiusMultiplier` - how forgiving checkpoint detection is: a checkpoint counts when the car is within `radius × this`. `>1` makes it easier to register (useful for decorated, marker-less gates whose props sit near the radius edge). `1.0` = exactly the radius.

### Object library (`editorObjects`)

The prop picker in the track creator.

* `custom` - add your own props: `{ model = 'name', image = 'picture URL for the tile' }`.
* `removed` - hide props you don't want (by model name).
* `categories` - the side-menu groups. A prop joins the first group whose keyword appears in its name; the rest go to "Other". Edit keywords or add a group (give it a `key`/`label`).

### Misc display & HUD

* `abandonCommand` - command to leave a race (players are reminded of it when they join).
* `leaderboardTopRightYOffset` - moves the top-right leaderboard down if it overlaps your other HUD (≈1 = 1px).
* `dragCountdownLength` - drag race countdown start number (normal races always count from 3).
* `checkpointDrawType` - how checkpoints are drawn: `"dui"` (nicer) or `"3dtext"` (lighter on performance).
* `disableRacesNotifications` - public races show a "race starting" notification; turn it off here.
* `disableRacesBlips` - public races show a map blip; turn it off here.

### Payments & prize pool

* `paymentMethod` - where entry money comes from: `"money"` (cash), `"bank"`, or `"both"`.
* `rewards` - prize pool: entry fees go into one pot, paid out by finishing position.
  * `enabled` - ON = entry fees form a prize pot, shared out below. OFF = fees just taken, no payout.
  * `distribution` - pot share per place: `{ 1.0 }` = winner takes all, `{ 0.6, 0.3, 0.1 }` = top 3. Should add up to 1 or less.
  * `houseCut` - server's cut of the pot, 0-1 (e.g. `0.05` keeps 5%).
  * `account` - where winnings are paid: `"money"` or `"bank"`.
  * `minRacers` - racers needed for the pot to pay out.
  * `refundBelowMinimum` - if too few racers take part, refund their fees instead of paying out.
* `priceLimits` - min/max entry fee a player can set when creating a race.

### Weather & word filter

* `availableWeathers` - weather options players can choose for a race.
* `blockedKeyWords` - banned words for track names, descriptions and nicknames.

### Server config (`config_server.lua`)

* `DefaultNicknamePrefix` - start of the auto-made nickname for new players, e.g. `"Driver 1234"`.
* `UsedIdentifier` - which player ID to save players by: `'steam'`, `'license'`, `'license2'`, `'discord'`, etc.
* `webhooks` - Discord logging. `enabled` is the master switch; for each event paste your webhook URL (a blank URL is skipped, so you can enable the master switch and only fill the events you want logged). Each event has `webhook` (URL), `title` and `color` (embed colour).
  * `raceFinished` - final standings + ELO changes + payouts (the important one).
  * `raceCreated` - a player hosted a new race.
  * `trackCreated` - a player saved a new track in the creator.
  * `trackDeleted` - a track was deleted.
