RE:CORD
REC_Hud

Stracture

Installation, configuration, and usage for REC_Hud.
Added
Updated

The following configuration files and manifest are taken from the current source.

config/sh_config.lua

---@class REC_Hud.Shared.Config
local config = {}

---[[
---    Debug Mode
---]]
---@type boolean
config.debugMode = true

---[[
---     Layout of every element the HUD draws
---
---     Every element has a default position here (a corner plus the distance from the screen edge).
---     Players can drag the elements anywhere from the layout editor (/rechudlayout, or the button in
---     the settings panel), that position is saved on their computer and wins over the one below.
---]]
config.ui = {

    ---[[
    ---     Hide the whole HUD while the pause menu is open
    ---]]
    ---@type boolean
    hideInPauseMenu = true,

    ---[[
    ---     Nothing is drawn until the player really stands in the world (loading screen gone, screen
    ---     faded in, no switch camera). This is how often that is checked (ms)
    ---]]
    ---@type integer
    spawnPoll = 250,

    ---[[
    ---     Chat commands
    ---]]
    command = {

        ---@type string # settings panel (shape, size, display mode, which gauges to show, ...)
        settings = "hud",

        ---@type string # layout editor (drag the elements around)
        layout = "layout",

        ---@type string # cinematic mode on / off (black bars, no HUD, no radar)
        cinematic = "cinematic",
    },

    ---[[
    ---     Key that opens the settings panel (the same panel as the command)
    ---]]
    settingsKeybind = {
        ---@type boolean
        enabled = true,

        ---@type string
        name = "rec_hud_settings",

        ---@type string # empty leaves it unbound, the player sets it in the key settings
        defaultKey = "I",
    },

    ---[[
    ---     Status gauges (health, hunger, ...)
    ---]]
    gauges = {

        ---[[
        ---     false hides the gauges entirely (keep it off when another HUD resource draws them)
        ---]]
        ---@type boolean
        enabled = true,

        ---[[
        ---     Corner the gauges sit in and the distance from the screen edge (CSS units)
        ---]]
        ---@type REC_Hud.Shared.Enum.Position
        position = "bottom-left",
        offset = {
            ---@type string
            x = "1.6vw",
            ---@type string
            y = "3vh",
        },
        ---@type string
        gap = "8px",

        ---[[
        ---     Default shape, players can pick another one from the settings panel
        ---     see enum.gaugeShape in shared/sh_enum.lua for the whole list
        ---     ("bar" / "thick" / "segment" / "ring" / "dial" / "needle" / "arc" / "column" / "columnSegment" /
        ---      "square" / "hex" / "diamond" / "minimal" / "number")
        ---]]
        ---@type REC_Hud.Shared.Enum.GaugeShape
        shape = "bar",

        ---[[
        ---     false locks the shape above (the settings panel hides the shape picker)
        ---]]
        ---@type boolean
        allowShapeChange = true,

        ---[[
        ---     Size multiplier (1.0 is the native size, players can change it from the settings panel)
        ---]]
        ---@type number
        scale = 1.5,

        ---[[
        ---     Default display mode, players can switch it from the settings panel
        ---     "always":   the gauges stay on screen
        ---     "onChange": a gauge is on screen while its value differs from its resting value
        ---                 (the item's "default" below) and hides again once it is back to it
        ---]]
        ---@type REC_Hud.Shared.Enum.DisplayMode
        displayMode = "always",

        ---@type number # below this percent the gauge blinks
        lowPercent = 20,

        ---[[
        ---     How often the values are read (ms)
        ---     only the values that changed are sent to the NUI
        ---]]
        ---@type integer
        tick = 300,

        ---[[
        ---     The gauges, drawn in this order
        ---     key:           unique name (also what exports.REC_Hud:setGaugeValue refers to)
        ---     icon:          an icon from shared/sh_enum.lua or a custom SVG path ("path:M12 2L...")
        ---     source:        where the value comes from
        ---                    a name from enum.gaugeSource (health / armor / stamina / oxygen come from natives,
        ---                    hunger / thirst / stress come from the framework through REC_Utils)
        ---                    or a function returning the value (nil hides the gauge until it returns one)
        ---                    omit it to push the value from another resource with exports.REC_Hud:setGaugeValue
        ---     min / max:     value range (defaults 0 to 100)
        ---     default:       resting value the "onChange" mode compares against
        ---                    (defaults to min when hideWhenEmpty is true, max otherwise)
        ---     hideWhenFull:  hide the gauge while the value is at max (stamina, oxygen)
        ---     hideWhenEmpty: hide the gauge while the value is at min (armor, stress)
        ---                    (both are ignored by the "always" mode, a gauge set to it stays on screen)
        ---     showValue:     draw the number next to the gauge
        ---     label:         name in the settings panel (defaults to locales.gauge[key], then the key)
        ---]]
        ---@type REC_Hud.Shared.Gauge.Payload[]
        items = {
            { key = "health",  icon = "heart",    color = "#f87171", source = "health", },
            { key = "armor",   icon = "shield",   color = "#60a5fa", source = "armor",   hideWhenEmpty = true, },
            { key = "hunger",  icon = "utensils", color = "#fbbf24", source = "hunger", },
            { key = "thirst",  icon = "droplet",  color = "#38bdf8", source = "thirst", },
            { key = "stress",  icon = "brain",    color = "#c084fc", source = "stress",  hideWhenEmpty = true, },
            { key = "stamina", icon = "activity", color = "#4ade80", source = "stamina", hideWhenFull = true, },
            { key = "oxygen",  icon = "waves",    color = "#22d3ee", source = "oxygen",  hideWhenFull = true, },

            -- a gauge fed by another resource, here the gas mask filter of REC_BetterMask
            -- {
            --     key = "maskFilter",
            --     icon = "mask",
            --     color = "#a3e635",
            --     hideWhenEmpty = true,
            --     source = function ()
            --         if GetResourceState("REC_BetterMask") ~= "started" then
            --             return nil
            --         end
            --         local state = exports.REC_BetterMask:getMaskState()
            --         if state == nil or state.wearing == false then
            --             return nil
            --         end
            --         return state.filter
            --     end,
            -- },
        },
    },

    ---[[
    ---     Vehicle panel, shown while the player sits in a vehicle
    ---     (a speed readout plus gauges read from the vehicle)
    ---]]
    vehicle = {

        ---@type boolean
        enabled = true,

        ---@type boolean # true shows the panel to the driver only
        driverOnly = false,

        ---@type REC_Hud.Shared.Enum.Position
        position = "bottom-right",
        offset = {
            ---@type string
            x = "1.6vw",
            ---@type string
            y = "3vh",
        },
        ---@type string
        gap = "8px",

        ---[[
        ---     Shape of the vehicle gauges, nil follows the status gauges
        ---]]
        ---@type REC_Hud.Shared.Enum.GaugeShape|nil
        shape = nil,

        ---@type integer # how often the vehicle is read (ms), the speed needs a quick tick
        tick = 100,

        ---[[
        ---     Speed readout
        ---]]
        speed = {
            ---@type boolean
            enabled = true,
            ---@type REC_Hud.Shared.Enum.SpeedUnit # default unit, players can switch it from the settings panel
            unit = "kmh",
            ---@type REC_Hud.Shared.Enum.SpeedStyle # "digital" is the number, "analog" a meter with a needle (players can switch)
            style = "digital",
            ---@type number # where the analog meter ends (in the unit above)
            max = 240,
            ---@type boolean # the needles kick when the gearbox shifts (analog meter and needle shaped gauges)
            shiftShake = true,
        },

        ---[[
        ---     Seatbelt: a warning icon while the belt is off, a soft chime once the vehicle moves
        ---     The belt itself lives here too (keybind, no ejection through the windscreen, no exit while buckled)
        ---     and is published as LocalPlayer.state[stateBag] for other resources
        ---]]
        seatbelt = {
            ---@type boolean
            enabled = true,

            ---@type string # LocalPlayer.state key, true while buckled
            stateBag = "seatbelt",

            keybind = {
                ---@type boolean # false leaves the toggling to exports.REC_Hud:setSeatbelt
                enabled = true,
                ---@type string
                name = "rec_hud_seatbelt",
                ---@type string
                defaultKey = "B",
            },

            ---@type boolean # the exit key does nothing while buckled
            blockExit = true,

            ---@type table<integer, boolean> # vehicle classes without a belt (no icon, no chime, no toggle)
            excludedClasses = {
                [8]  = true, -- motorcycles
                [13] = true, -- cycles
            },

            ---[[
            ---     The reminder chime (players can mute it from the settings panel)
            ---]]
            sound = {
                ---@type boolean
                enabled = true,

                ---@type number # km/h, no chime below this speed
                minSpeed = 15,

                ---@type integer # ms between two chimes
                interval = 1800,

                ---@type number # 0 to 1
                volume = 0.05,
            },
        },

        ---[[
        ---     Aircraft (planes and helicopters) get an airspeed, altitude, climb and heading readout
        ---     on top of the gauges below
        ---]]
        aircraft = {
            ---@type boolean # false draws the plain vehicle panel in aircraft too
            enabled = true,

            ---@type REC_Hud.Shared.Enum.SpeedUnit # "kmh" / "mph" / "knots" (players can switch)
            speedUnit = "knots",

            ---@type number # where the analog airspeed meter ends (in the unit above)
            speedMax = 300,

            ---@type REC_Hud.Shared.Enum.AltitudeUnit # "m" / "ft" (players can switch)
            altitudeUnit = "ft",
        },

        ---[[
        ---     The gauges read from the vehicle, same fields as config.ui.gauges.items
        ---     source: a name from enum.vehicleSource (fuel / engine / body / rpm)
        ---             or a function (vehicle) returning the value
        ---]]
        ---@type REC_Hud.Shared.Gauge.Payload[]
        items = {
            { key = "fuel",   icon = "fuel",   color = "#f59e0b", source = "fuel",   showValue = false, unit = "%", }, -- players can turn the percent readout on from the settings panel
            { key = "engine", icon = "engine", color = "#ef4444", source = "engine", },
            -- { key = "body", icon = "wrench", color = "#a3a3a3", source = "body", },
            -- { key = "rpm",  icon = "gauge",  color = "#38bdf8", source = "rpm", },
        },
    },

    ---[[
    ---     Clock (players can turn it off, switch 12h / 24h, seconds and the date from the settings panel)
    ---]]
    clock = {

        ---@type boolean
        enabled = true,

        ---@type REC_Hud.Shared.Enum.Position
        position = "top-right",
        offset = {
            ---@type string
            x = "1.6vw",
            ---@type string
            y = "2vh",
        },

        ---@type REC_Hud.Shared.Enum.ClockSource # "real" is the player's computer, "game" the in-game time
        source = "real",

        ---@type boolean # 12 hour clock with AM / PM
        hour12 = false,

        ---@type boolean
        showSeconds = false,

        ---@type boolean # the date under the time ("real" only)
        showDate = false,
    },

    ---[[
    ---     Server ID of the player
    ---     the number the staff asks for, it never changes while the player is connected
    ---
    ---     While it shares its corner with the clock it is drawn right under it whatever the clock
    ---     shows, so the offset below is only used when they sit in different corners
    ---]]
    serverId = {

        ---@type boolean
        enabled = true,

        ---@type REC_Hud.Shared.Enum.Position
        position = "top-right",
        offset = {
            ---@type string
            x = "1.6vw",
            ---@type string
            y = "7vh",
        },

        ---@type boolean # draw the "ID" label in front of the number
        showLabel = true,
    },

    ---[[
    ---     FiveM player name, stacked below the server ID or clock while sharing their corner
    ---]]
    playerName = {

        ---@type boolean
        enabled = true,

        ---@type boolean # false prevents players from hiding the name; layout editing stays available
        allowHide = false,

        ---@type REC_Hud.Shared.Enum.Position
        position = "top-right",
        offset = {
            ---@type string
            x = "1.6vw",
            ---@type string
            y = "11vh",
        },
    },

    ---[[
    ---     Compass
    ---     a bar with the cardinals and the ticks, the heading in degrees and the street names under it
    ---]]
    compass = {

        ---@type boolean
        enabled = true,

        ---@type REC_Hud.Shared.Enum.Position
        position = "top-center",
        offset = {
            ---@type string
            x = "0px",
            ---@type string
            y = "1.5vh",
        },

        ---@type string # CSS width of the bar
        width = "340px",

        ---@type boolean # only while in a vehicle (the settings panel can change it)
        inVehicleOnly = true,

        ---@type boolean # follow the camera heading, false follows the ped
        followCamera = true,

        ---@type boolean # the heading in degrees under the bar
        showDegrees = true,

        ---@type boolean # the marker in the middle of the bar
        showPointer = true,

        ---@type boolean # the street names under the bar
        showStreets = true,

        ---@type integer # how often the heading is read (ms)
        tick = 50,

        ---@type integer # how often the street names are read (ms)
        streetTick = 1000,
    },

    ---[[
    ---     Server logo
    ---     image: a file inside this resource (listed under files in fxmanifest.lua) or a full URL,
    ---            nil draws the text instead
    ---]]
    logo = {

        ---@type boolean
        enabled = false,

        ---@type REC_Hud.Shared.Enum.Position
        position = "top-left",
        offset = {
            ---@type string
            x = "1.6vw",
            ---@type string
            y = "2vh",
        },

        ---@type string|nil
        image = "images/logo.svg",

        ---@type string # drawn when image is nil (or fails to load)
        text = "RE:CORD",

        ---@type string # CSS width of the image
        width = "140px",

        ---@type number # 0 to 1
        opacity = 0.9,
    },

    ---[[
    ---     Minimap
    ---     the map itself is drawn by the game, REC_Hud only moves it (SetMinimapComponentPosition)
    ---     to where the player dragged its outline in the layout editor
    ---]]
    minimap = {

        ---@type boolean # false leaves the minimap alone (no outline in the layout editor)
        movable = true,

        ---[[
        ---     Shape of the minimap: the radar mask is swapped for the one streamed from stream/
        ---     (squaremap.ytd / circlemap.ytd, the minimap.gfx there drops the vanilla frame and bars)
        ---     nil keeps the vanilla minimap, players can pick a shape from the settings panel
        ---]]
        ---@type REC_Hud.Shared.Enum.MinimapShape|nil
        shape = "square",

        ---@type number # size of the minimap, 1.0 is the vanilla size (players can change it, min / max below)
        scale = 1.0,

        ---@type number
        scaleMin = 0.6,

        ---@type number
        scaleMax = 1.8,

        ---@type boolean # hide the north blip on the radar
        hideNorthBlip = true,

        ---@type boolean # draw the radar on foot too, false shows it in vehicles only (players can switch)
        showOnFoot = true,

        ---@type integer # ms, the shape / size is applied a second time this long after a spawn (the game resets the minimap while spawning)
        reapplyDelay = 2000,

        ---[[
        ---     Radar keep-alive
        ---     other resources set the radar zoom and can leave the bigmap on after this resource
        ---     has applied its own state (map_code adds its minimap overlay from the end of the
        ---     resource list), and none of them announce it, so the state is set again when a
        ---     resource starts after this one, and on a slow interval as a fallback.
        ---     ps-hud did the same every 500 ms.
        ---]]
        ---@type integer # ms between each fallback re-assert (a resource starting after this one re-asserts right away), 0 disables the keep-alive
        keepAliveInterval = 2000,

        ---@type integer|nil # radar zoom the keep-alive forces, nil leaves the zoom alone
        radarZoom = 1000,
    },

    ---[[
    ---     Vanilla HUD parts hidden every frame (the thread only runs while the list is not empty)
    ---     1 wanted stars, 2 weapon icon, 3 cash, 4 MP cash, 6 vehicle name, 7 area name,
    ---     8 vehicle class, 9 street name, 13 cash change, 17 save game, 20 weapon wheel stats
    ---]]
    ---@type integer[]
    hideComponents = { 1, 2, 3, 4, 13, 17, 20, },

    ---[[
    ---     Cinematic mode: black bars slide in, the HUD and the radar go away (/cinematic or the keybind)
    ---]]
    cinematic = {

        ---@type boolean
        enabled = true,

        ---@type number # height of one bar, fraction of the screen
        barHeight = 0.12,

        ---@type integer # ms the bars take to slide in / out
        duration = 400,

        keybind = {
            ---@type boolean
            enabled = true,

            ---@type string
            name = "rec_hud_cinematic",

            ---@type string # empty leaves it unbound, the player sets it in the key settings
            defaultKey = "",
        },
    },
}

---@type REC_Hud.Shared.Preset
local preset = require "@REC_Hud.shared.sh_preset"

---@type table # paste an exported preset into config/ui_defaults.json
config.defaultPrefs = preset:load(config.ui)

return config
©2026 RE:CORD Development Group. All rights reserved.