> For the complete documentation index, see [llms.txt](https://project-07.gitbook.io/project_07-docs/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://project-07.gitbook.io/project_07-docs/scripts/project07-radialmenu-v2/configuration.md).

# Configuration

Config Files

{% tabs %}
{% tab title="Config.lua" %}
{% code title="" overflow="wrap" lineNumbers="true" %}

```lua
RadialConfig = {}

-- ── KEYBIND ──────────────────────────────────────────────────
RadialConfig.keybindKey         = 'f1'              -- Default open/close key
RadialConfig.keybindName        = 'openRadialMenu'
RadialConfig.keybindDescription = locale('general.command_description')

-- ── CUSTOMIZATION BUTTON ─────────────────────────────────────
RadialConfig.enableSettingsButton = true

-- ── GENERAL ──────────────────────────────────────────────────
RadialConfig.enableExtraMenu = true    -- Vehicle extras grid-panel enable/disable
RadialConfig.flipTime        = 15000   -- Vehicle flip progress bar duration (ms)

-- ── MOVEMENT LOCK ─────────────────────────────────────────────
-- Combat/attack controls are ALWAYS disabled while the radial is open
-- (clicking a menu button must never punch/fire — see client/nui_bridge.lua).
-- This section only controls whether movement itself also gets locked.
RadialConfig.movementLock = {
    enabled       = false,   -- true = movement lock on | false = off
    disableMove   = false,   -- WASD disable
    disableSprint = false,   -- Sprint disable
}

-- ── TRUNK CLASSES ─────────────────────────────────────────────
RadialConfig.trunkClasses = {
    [0]  = {allowed=true,  x=0.0, y=-1.5, z=0.0},   -- Coupes
    [1]  = {allowed=true,  x=0.0, y=-2.0, z=0.0},   -- Sedans
    [2]  = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- SUVs
    [3]  = {allowed=true,  x=0.0, y=-1.5, z=0.0},   -- Coupes
    [4]  = {allowed=true,  x=0.0, y=-2.0, z=0.0},   -- Muscle
    [5]  = {allowed=true,  x=0.0, y=-2.0, z=0.0},   -- Sports Classics
    [6]  = {allowed=true,  x=0.0, y=-2.0, z=0.0},   -- Sports
    [7]  = {allowed=true,  x=0.0, y=-2.0, z=0.0},   -- Super
    [8]  = {allowed=false, x=0.0, y=-1.0, z=0.25},  -- Motorcycles
    [9]  = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Off-road
    [10] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Industrial
    [11] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Utility
    [12] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Vans
    [13] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Cycles
    [14] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Boats
    [15] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Helicopters
    [16] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Planes
    [17] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Service
    [18] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Emergency
    [19] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Military
    [20] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Commercial
    [21] = {allowed=true,  x=0.0, y=-1.0, z=0.25},  -- Trains
}

-- Menu items live in config/items.lua
-- Framework/job-mapping/ox_lib-bridge settings live in config/framework.lua

```

{% endcode %}
{% endtab %}

{% tab title="Framework.lua" %}

```lua
FrameworkConfig = {}

-- ── JOB → TYPE MAPPING (ESX only) ───────────────────────────────
-- QBX/QBCore already expose job.type ('leo'/'ems') natively, so this table
-- is only consulted by the ESX branch of the framework bridge in
-- client/main.lua, which has no such concept built in.
FrameworkConfig.LeoJobs = { police = true, sheriff = true, state = true }
FrameworkConfig.EmsJobs = { ambulance = true, ems = true }

-- ── NOTIFICATIONS ────────────────────────────────────────────────
-- Fallback values used if the detected framework's notify function doesn't
-- take a position/duration itself.
FrameworkConfig.NotifyDuration = 4000
FrameworkConfig.NotifyPosition = 'top'

-- ── OX_LIB RADIAL BRIDGE ─────────────────────────────────────────
-- This resource does NOT depend on ox_lib and never calls it. This section
-- only documents/toggles the bridge shipped in bridge/ox_lib_radial_override.lua,
-- which is a drop-in replacement for ox_lib's OWN radial.lua (see that file's
-- header comment for install steps). It routes any third-party script's
-- lib.registerRadial / lib.addRadialItem / etc calls into THIS resource's
-- menu instead of ox_lib's plain default radial UI.
FrameworkConfig.OxLibBridge = {
    enabled     = true,   -- informational — the actual bridge file must be installed manually
    defaultPage = 'main',
}

```

{% endtab %}

{% tab title="Items.lua" %}

```lua
-- ============================================
-- items.lua — the actual radial menu tree
-- (keybinds/toggles/theme-adjacent settings live in config/config.lua,
--  framework/job-mapping/ox_lib-bridge settings live in config/framework.lua)
--
-- icon names: https://fontawesome.com/icons (free solid, FA6 names)
-- event = client event | serverEvent = server event | command = /command
-- Only set ONE of event/serverEvent/command/onSelect per item — the first
-- one present wins (see client/nui_bridge.lua's executeItem). `args` is
-- optional and gets passed through to whichever one you used.
-- Labels come from locales/<lang>.json under "items.<id>" — edit the text
-- there, not here, to change what players see (or to add another language).
-- ============================================

RadialConfig.menuItems = {
    {
        id='citizen', icon='user', label=locale('items.citizen'),
        items = {
            { id='givenum',       icon='address-book',       label=locale('items.givenum'),       event='qb-phone:client:GiveContactDetails' },
            { id='getintrunk',    icon='car',                label=locale('items.getintrunk'),    event='qb-trunk:client:GetIn' },
            { id='cornerselling', icon='cannabis',           label=locale('items.cornerselling'), event='qb-drugs:client:cornerselling' },
            -- `command` runs a chat command instead of firing an event — useful for
            -- scripts that only expose a /command (no exported event to hook into).
            -- `args` is optional; if set, it's appended after the command name.
          --  { id='surrender',     icon='hands',               label=locale('items.surrender'),     command='handsup' },
            {
                id='interactions', icon='exclamation-triangle', label=locale('items.interactions'),
                items = {
                    { id='handcuff',         icon='user-lock',  label=locale('items.handcuff'),         event='police:client:CuffPlayer' },
                    { id='playerInVehicle',  icon='car-side',   label=locale('items.playerInVehicle'),  event='police:client:PutPlayerInVehicle' },
                    { id='playerOutVehicle', icon='car-side',   label=locale('items.playerOutVehicle'), event='police:client:SetPlayerOutVehicle' },
                    { id='stealPlayer',      icon='mask',       label=locale('items.stealPlayer'),      event='police:client:RobPlayer' },
                    { id='kidnapPlayer',     icon='user-group', label=locale('items.kidnapPlayer'),     event='police:client:KidnapPlayer' },
                    { id='escortPlayer',     icon='user-group', label=locale('items.escortPlayer'),     event='police:client:EscortPlayer' },
                    { id='takeHostage',      icon='child',      label=locale('items.takeHostage'),      event='police:client:TakeHostage' },
                },
            },
        },
    },
    {
        id='general', icon='rectangle-list', label=locale('items.general'),
        items = {
            {
                id='clothesMenu', icon='shirt', label=locale('items.clothesMenu'),
                items = {
                    { id='hair',  icon='user',        label=locale('items.hair'),  event='qb-radialmenu:ToggleClothing', args={id='Hair'} },
                    { id='ear',   icon='ear-deaf',    label=locale('items.ear'),   event='qb-radialmenu:ToggleProps',    args='Ear' },
                    { id='neck',  icon='user-tie',    label=locale('items.neck'),  event='qb-radialmenu:ToggleClothing', args={id='Neck'} },
                    { id='top',   icon='shirt',       label=locale('items.top'),   event='qb-radialmenu:ToggleClothing', args={id='Top'} },
                    { id='shirt', icon='shirt',       label=locale('items.shirt'), event='qb-radialmenu:ToggleClothing', args={id='Shirt'} },
                    { id='pants', icon='user',        label=locale('items.pants'), event='qb-radialmenu:ToggleClothing', args={id='Pants'} },
                    { id='shoes', icon='shoe-prints', label=locale('items.shoes'), event='qb-radialmenu:ToggleClothing', args={id='Shoes'} },
                    {
                        id='clothingExtras', icon='plus', label=locale('items.clothingExtras'),
                        items = {
                            { id='hat',      icon='hat-cowboy-side', label=locale('items.hat'),      event='qb-radialmenu:ToggleProps',    args='Hat' },
                            { id='glasses',  icon='glasses',         label=locale('items.glasses'),  event='qb-radialmenu:ToggleProps',    args='Glasses' },
                            { id='visor',    icon='hat-cowboy-side', label=locale('items.visor'),    event='qb-radialmenu:ToggleProps',    args='Visor' },
                            { id='mask',     icon='masks-theater',   label=locale('items.mask'),     event='qb-radialmenu:ToggleClothing', args={id='Mask'} },
                            { id='vest',     icon='vest',            label=locale('items.vest'),     event='qb-radialmenu:ToggleClothing', args={id='Vest'} },
                            { id='bag',      icon='bag',             label=locale('items.bag'),      event='qb-radialmenu:ToggleClothing', args={id='Bag'} },
                            { id='bracelet', icon='user',            label=locale('items.bracelet'), event='qb-radialmenu:ToggleProps',    args='Bracelet' },
                            { id='watch',    icon='stopwatch',       label=locale('items.watch'),    event='qb-radialmenu:ToggleProps',    args='Watch' },
                            { id='gloves',   icon='mitten',          label=locale('items.gloves'),   event='qb-radialmenu:ToggleClothing', args={id='Gloves'} },
                        },
                    },
                },
            },
        },
    },
}

-- ── JOB ITEMS ─────────────────────────────────────────────────
-- Job name must match your framework's job name exactly (lowercase)
RadialConfig.jobItems = {
    police = {
        { id='emergencyButton',      icon='bell',       label=locale('items.emergencyButton'),      event='police:client:SendPoliceEmergencyAlert' },
        { id='resetHouse',           icon='key',        label=locale('items.resetHouse'),           event='qb-houses:client:ResetHouse' },
        { id='revokeDriversLicense', icon='id-card',    label=locale('items.revokeDriversLicense'), event='police:client:SeizeDriverLicense' },
        {
            id='policeInteractions', icon='list-check', label=locale('items.policeInteractions'),
            items = {
                { id='statusCheck', icon='heart-pulse',      label=locale('items.statusCheck'), event='hospital:client:CheckStatus' },
                { id='escort',      icon='user-group',       label=locale('items.escort'),      event='police:client:EscortPlayer' },
                { id='search',      icon='magnifying-glass', label=locale('items.search'),      event='police:client:SearchPlayer' },
                { id='jail',        icon='user-lock',        label=locale('items.jail'),        event='police:client:JailPlayer' },
            },
        },
        {
            id='policeObjects', icon='road', label=locale('items.policeObjects'),
            items = {
                { id='cone',         icon='triangle-exclamation', label=locale('items.cone'),         event='police:client:spawnPObj', args='cone' },
                { id='gate',         icon='torii-gate',           label=locale('items.gate'),         event='police:client:spawnPObj', args='barrier' },
                { id='speedSign',    icon='sign-hanging',         label=locale('items.speedSign'),    event='police:client:spawnPObj', args='roadsign' },
                { id='tent',         icon='campground',           label=locale('items.tent'),         event='police:client:spawnPObj', args='tent' },
                { id='lighting',     icon='lightbulb',            label=locale('items.lighting'),     event='police:client:spawnPObj', args='light' },
                { id='spikeStrip',   icon='caret-up',             label=locale('items.spikeStrip'),   event='police:client:SpawnSpikeStrip' },
                { id='deleteObject', icon='trash',                label=locale('items.deleteObject'), event='police:client:deleteObject' },
            },
        },
    },
    ambulance = {
        { id='statusCheck',     icon='heart-pulse', label=locale('items.statusCheck'),     event='hospital:client:CheckStatus' },
        { id='revive',          icon='user-doctor', label=locale('items.revive'),          event='hospital:client:RevivePlayer' },
        { id='treatWounds',     icon='bandage',     label=locale('items.treatWounds'),     event='hospital:client:TreatWounds' },
        { id='emergencyButton', icon='bell',        label=locale('items.emergencyButton'), serverEvent='hospital:server:emergencyAlert' },
        { id='escort',          icon='user-group',  label=locale('items.escort'),          event='police:client:EscortPlayer' },
    },
    mechanic = {
        { id='towVehicle', icon='truck-pickup', label=locale('items.towVehicle'), event='qb-tow:client:TowVehicle' },
    },
    taxi = {
        { id='togglemeter', icon='eye-slash',       label=locale('items.togglemeter'), event='qb-taxi:client:toggleMeter' },
        { id='togglemouse', icon='hourglass-start', label=locale('items.togglemouse'), event='qb-taxi:client:enableMeter' },
        { id='npcMission',  icon='taxi',            label=locale('items.npcMission'),  event='qb-taxi:client:DoTaxiNpc' },
    },
    tow = {
        { id='togglenpc',  icon='toggle-on',   label=locale('items.togglenpc'),  event='jobs:client:ToggleNpc' },
        { id='towVehicle', icon='truck-pickup', label=locale('items.towVehicle'), event='qb-tow:client:TowVehicle' },
    },
}

-- ── GANG ITEMS ────────────────────────────────────────────────
-- Gang name must match your framework's gang name (lowercase). Empty = no gang menu
RadialConfig.gangItems = {
    -- example:
    -- ballas = {
    --     { id='gangAction', icon='skull-crossbones', label=locale('items.gangAction'), event='gangs:client:someEvent' },
    -- },
}

-- ── CLOTHING WHEEL COMMANDS ───────────────────────────────────
-- /top /gloves /hat etc. in-game commands (the small clothing dial, separate
-- from the radial menu's own Clothing submenu above)
RadialConfig.clothingCommands = {
    top      = { Func=function() ToggleClothing({'Top'})         end, Sprite='top',      Desc='Take your shirt off/on',          Button=1,  Name='Torso'    },
    gloves   = { Func=function() ToggleClothing({'Gloves'})      end, Sprite='gloves',   Desc='Take your gloves off/on',         Button=2,  Name='Gloves'   },
    visor    = { Func=function() ToggleProps({'Visor'})          end, Sprite='visor',    Desc='Toggle hat variation',            Button=3,  Name='Visor'    },
    bag      = { Func=function() ToggleClothing({'Bag'})         end, Sprite='bag',      Desc='Opens or closes your bag',        Button=8,  Name='Bag'      },
    shoes    = { Func=function() ToggleClothing({'Shoes'})       end, Sprite='shoes',    Desc='Take your shoes off/on',          Button=5,  Name='Shoes'    },
    vest     = { Func=function() ToggleClothing({'Vest'})        end, Sprite='vest',     Desc='Take your vest off/on',           Button=14, Name='Vest'     },
    hair     = { Func=function() ToggleClothing({'Hair'})        end, Sprite='hair',     Desc='Put your hair up/down',           Button=7,  Name='Hair'     },
    hat      = { Func=function() ToggleProps({'Hat'})            end, Sprite='hat',      Desc='Take your hat off/on',            Button=4,  Name='Hat'      },
    glasses  = { Func=function() ToggleProps({'Glasses'})        end, Sprite='glasses',  Desc='Take your glasses off/on',        Button=9,  Name='Glasses'  },
    ear      = { Func=function() ToggleProps({'Ear'})            end, Sprite='ear',      Desc='Take your ear accessory off/on',  Button=10, Name='Ear'      },
    neck     = { Func=function() ToggleClothing({'Neck'})        end, Sprite='neck',     Desc='Take your neck accessory off/on', Button=11, Name='Neck'     },
    watch    = { Func=function() ToggleProps({'Watch'})          end, Sprite='watch',    Desc='Take your watch off/on',          Button=12, Name='Watch',   Rotation=5.0 },
    bracelet = { Func=function() ToggleProps({'Bracelet'})       end, Sprite='bracelet', Desc='Take your bracelet off/on',       Button=13, Name='Bracelet' },
    mask     = { Func=function() ToggleClothing({'Mask'})        end, Sprite='mask',     Desc='Take your mask off/on',           Button=6,  Name='Mask'     },
    pants    = { Func=function() ToggleClothing({'Pants',true})  end, Sprite='pants',    Desc='Take your pants off/on',          Name='Pants',  OffsetX=-0.04, OffsetY=0.0 },
    shirt    = { Func=function() ToggleClothing({'Shirt',true})  end, Sprite='shirt',    Desc='Take your shirt off/on',          Name='shirt',  OffsetX=0.04,  OffsetY=0.0 },
    reset = {
        Func=function() if not ResetClothing(true) then Notify('Nothing To Reset','error') end end,
        Sprite='reset', Desc='Revert everything back to normal', Name='reset', OffsetX=0.12, OffsetY=0.2, Rotate=true,
    },
    bagoff = {
        Func=function() ToggleClothing({'Bagoff',true}) end,
        Sprite='bagoff',
        SpriteFunc=function()
            local bags={[40]=true,[41]=true,[44]=true,[45]=true}
            local Bag=GetPedDrawableVariation(cache.ped,5)
            local BagOff=LastEquipped['Bagoff']
            if LastEquipped['Bagoff'] then return bags[BagOff.Drawable] and 'bagoff' or 'paraoff' end
            if Bag~=0 then return bags[Bag] and 'bagoff' or 'paraoff' else return false end
        end,
        Desc='Take your bag off/on', Name='bagoff', OffsetX=-0.12, OffsetY=0.2,
    },
}

```

{% endtab %}

{% tab title="Theme.json" %}

```json
{
    "_comment": "Project07 Server Side Theme. Player KVP prefs override: accent/ring/ring2/cardHoverBg/shadow/text/label/buttonStyle/ringStyle/tiltEnabled/position/scale. cardBg and cardBorder are fixed/server-authoritative only (idle card look is not player-customizable).",

    "accent":       "#e53935",
    "cardBg":       "#000000a1",
    "cardBorder":   "#ffffff38",
    "cardHoverBg":  "#ffffff48",
    "shadowColor":  "#e539358c",
    "ringColor":    "#ffffff8c",
    "ring2Color":   "#e53935",
    "dimText":      "#ffffff73",
    "textColor":    "#ffffff",
    "labelColor":   "#e53935",

    "buttonStyle":  "notch",
    "ringStyle":    "dual",
    "tiltEnabled":  true,

    "orbitRadius":   190,
    "cardSize":      88,
    "containerSize": 380,

    "ringSpinSpeed":    70,
    "ringSpinReverse":  46,
    "popInDuration":    0.22,
    "cardInDuration":   0.22,
    "cardStagger":      0.035
}

```

{% endtab %}
{% endtabs %}
