Config File

Current annotated reference. Merge the settings you need into your existing config. Placeholder branding is used and demos are disabled in this example.

Lua
-- Server setup only. Players configure their interface with /hudedit.
-- Personal settings save per player; no server restart is needed to change them.
Config = Config or {}

Config.Installer = {
    enabled = true,
    oxLib = true,
    target = false,
    esx = false,
    qbCore = false,
}

Config.Logo = "https://your-server.com/logo.png"

Config.Chat = {
    maxMessages = 80,
    fadeTimeout = 7000,
    meDistance = 20.0,
    enabled = true,
    suggestionLimit = 6,
    openKey = "T",
    doDistance = 20.0,
    localDistance = 20.0,
}

Config.CustomThemePresets = {

}

Config.Brand = {
    name = "Your Server",
    logoUrl = "https://your-server.com/logo.png",
    mark = "",
}

-- Official server website. Leave empty to disable the Website button.
Config.Website = 'https://discord.gg/yourserver' -- e.g. https://your-server.com

Config.DiscordInvite = "https://discord.gg/yourserver"

Config.DemoEnabled = false

Config.DemoCommand = "fui"

Config.RadialKey = "X"

Config.ProgressCancelKey = "X"

Config.BlockWhenDead = true

Config.IncludeTotalPlaytime = false

-- Server integration policy (not a personal display preference).
Config.Interaction = {
    requireLos = true,
    maxIndicators = 6,
    enabled = true,
    duiScale = 0.2,
    compactIdleMs = 3500,
    requireLookAt = true,
    maxInteractDistance = 5.0,
    defaultInteractKey = "E",
    duiResolution = 2048,
    lookRadius = 0.07,
    compactOptions = true,
    replaceTargets = false,
}

-- Pause menu: server-wide settings, managed here rather than /hudedit.
Config.pausemenu = true

Config.OpenControls = {
    200,
    199,
}

Config.TimecycleModifier = "cinema"

Config.TimecycleStrength = 0.9

Config.Camera = {
    fov = 40.0,
    distance = 1.85,
    height = 0.45,
    easeMs = 650,
}

Config.Thinking = {
    label = "Thinking",
    scale = 0.36,
    enabled = true,
    drawDistance = 18.0,
    zOffset = 1.08,
    anim = {
        flag = 49,
        dict = "anim@mp_player_intupperthinking",
        clip = "idle_a",
    },
    color = {
        r = 230,
        a = 235,
        b = 180,
        g = 214,
    },
    animateDots = true,
}

Config.Transitions = {
    handoffMs = 700,
    uiMs = 300,
    exitMs = 3800,
}

Config.ExitQuotes = {
    "The streets remember every choice you make.",
    "In this city, silence can speak louder than sirens.",
    "Every goodbye is just another story unfinished.",
    "Keep your name clean — reputation travels faster than cars.",
    "The night is long, but character lasts longer.",
    "Walk away if you must. Just don't forget who you are.",
    "Some leave in peace. Others leave a legend.",
    "Los Santos never sleeps… but even legends need rest.",
    "Your story pauses here. The city keeps writing.",
    "Disconnecting from the world — not from who you became.",
}

-- Server-controlled UI behavior. /hudedit only exposes notification position.
Config.TextUIPosition = "right-center"
Config.ProgressCirclePosition = "middle"
Config.Timer = {
    position = "left-center",
    completionDisplayMs = 3000,
}
Config.UIVisibility = { notify = true, timer = true, textui = true, interaction = true }

-- Hologram behavior and placement are controlled by the server.
Config.Hud.hologram = {
    opacity = 255,
    onlyEngineRunning = true,
    enabled = true,
    maxDistance = 25.0,
    updateInterval = 50,
    hideInFirstPerson = true,
    resolution = 512,
    driverOnly = true,
    offset = {
        x = 2.5,
        y = -1.0,
        z = 0.85,
    },
    displayScale = 1.0,
    rotation = {
        x = 0.0,
        y = 0.0,
        z = -15.0,
    },
}

-- Microphone geometry limits. Voice visibility choices remain in /hudedit.
Config.Hud.voice3D.size = 0.17
Config.Hud.voice3D.maxDistance = 12.0
Config.Hud.voice3D.maxSpeakers = 6
Config.Hud.voice3D.offset = {
    side = 0.34,
    forward = 0.06,
    height = 0.015,
}

-- Dashboard permissions. Grant admins with: add_ace group.admin finals_ui.admin allow
Config.HudEditor = {
    command = 'hudedit',
    pauseMenuButton = true,           -- show Customize UI in pause, only for permitted players
    aliases = { 'fuiedit' },
    adminOnly = false,                -- true: only admins may open/edit the dashboard
    adminAce = 'finals_ui.admin',
    adminChangesGlobal = true,        -- admin Save applies to everyone and future joins
    playerPermissions = {
        sections = { hud = true, themes = true, map = true, ui = true, voice = true, performance = true, layout = true },
        settings = {
            -- false hides/locks one option for players (admins can still edit it):
            -- ['visibility.infoCash'] = false,
            -- ['Hud.map.shape'] = { options = { 'square' } },
            -- ['UiTheme'] = { options = { 'cyan', 'blue' } },
            -- ['statsStyle'] = false,
            -- ['layout.info_cash'] = false,
        },
        -- Optional allowed preset lists; omit a list to allow every preset.
        -- hudStyles = { 'classic', 'arc', 'square' },
        -- speedometerStyles = { 'classic', 'analog' },
        layoutScaleMin = 0.5,
        layoutScaleMax = 2.0,
    },
}

-- Pause poses only run on foot. Set changeEveryMs = 0 to keep one pose per opening.
Config.PauseAnimations = {
    enabled = true,
    changeEveryMs = 10000,
    poses = {
        { name = 'Folded arms', dict = 'amb@world_human_hang_out_street@female_arms_crossed@idle_a', clip = 'idle_a', flag = 49 },
        { name = 'Thinking', dict = 'anim@mp_player_intupperthinking', clip = 'idle_a', flag = 49 },
        { name = 'Relaxed arms', dict = 'amb@world_human_hang_out_street@male_c@idle_a', clip = 'idle_b', flag = 49 },
    },
}

-- Read from disk each time pause opens; JSON edits do not require a resource restart.
Config.PauseNews = { enabled = true, file = 'data/pause_news.json', maxEntries = 6 }

-- Player info: built-in qbox/qb/esx, native-only standalone, or your canonical custom reader.
Config.Framework = {
    type = 'auto', -- auto | qbox | qb | esx | standalone | custom
    resources = { qbox = 'qbx_core', qb = 'qb-core', esx = 'es_extended' },
    getPlayerData = false, -- function() return { charinfo={}, money={}, job={}, metadata={} } end
    isPlayerLoaded = false, -- optional function() return true/false end
    esxSecondJobAsGang = false,
}

-- Read-only fuel integration. All speedometers, including the hologram, share this reader.
Config.Fuel = {
    mode = 'auto', -- auto | native | statebag | export | custom | a GetFuel-compatible resource name
    resource = '',
    exportName = 'GetFuel',
    stateKey = 'fuel',
    maxValue = 100, -- 1 for a custom source returning 0..1; native fallback is always 0..100
    refreshMs = 500,
    get = false, -- function(vehicle) return exports['your-fuel']:GetFuel(vehicle) end
    providers = { 'LegacyFuel', 'ps-fuel', 'lj-fuel', 'qb-fuel', 'cdn-fuel', 'Renewed-Fuel', 'hex_3_fuel' },
}

-- Belt display integration; your existing seatbelt script keeps ownership of belt physics/keybinds.
Config.Seatbelt = {
    mode = 'auto', -- auto | statebag | event | export | custom
    stateKey = 'seatbelt',
    harnessKey = 'harness',
    resource = '',
    exportName = 'IsSeatbeltOn',
    passVehicle = false,
    get = false, -- function(vehicle) return exports['your-belt']:IsSeatbeltOn() end
    event = '', -- e.g. 'your-belt:stateChanged'; empty auto listens to QB's ToggleSeatbelt event
    eventMode = 'state', -- state: receives true/false; toggle: event has no state argument
    eventArgument = 1,
    eventField = false, -- e.g. 'buckled' if the event argument is { buckled = true }
    toggle = { type = 'none', resource = '', name = '', passVehicle = false }, -- none | event | export | command
    command = 'fuiseatbelt', -- registered only when toggle.type is configured
    key = false, -- optional keyboard key; false avoids duplicating the original belt keybind
}