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

# World, Camera & Scene

Spawn routing, world coordinates, camera framing, time / weather lock, and the 3-point lighting + props + ground ring scene rig.

{% tabs %}
{% tab title="QBCore" %}

```lua

-- ════════════════════════════════════════════════════════════════
--  WORLD / CAMERA / PED PREVIEW
-- ════════════════════════════════════════════════════════════════
-- ── SPAWN ROUTING ──────────────────────────────────────────
-- After Login, where does the player end up?
--   'spawnSelector' → triggers qb-spawn:client:openUI (also caught by
--                     feron_spawnSelector). Spawn UI lets player pick.
--   'apartments'    → triggers apartments:client:setupSpawnUI
--                     (qb-apartments). Routes through apartment.
--   'lastLocation'  → teleport directly to players.position (no UI).
--   'custom'        → invokes Config.OnCustomSpawn (see below). Use
--                     this to integrate any spawn selector that
--                     isn't qb-spawn / qb-apartments (vms_spawnselector,
--                     um-spawn, your own UI).
--   'auto'          → detect qb-apartments / feron_spawnSelector / qb-spawn
--                     / Config.OnCustomSpawn and pick the most
--                     appropriate flow.
Config.SpawnFlow = 'auto'

-- Custom spawn handler — fired when SpawnFlow resolves to 'custom'.
-- Receives source + citizenid + last-known position + character info.
-- Trigger your spawn selector / cutscene here.
Config.OnCustomSpawn = nil
-- Example:
-- Config.OnCustomSpawn = function(src, citizenid, position, charinfo)
--     TriggerClientEvent('vms_spawnselector:open', src, charinfo, position)
-- end

-- Legacy toggles, kept for backwards-compat but superseded by SpawnFlow.
Config.UseQbApartments         = false
Config.UseEsxStartingApartment = false

-- ── PREVIEW LOCATION ────────────────────────────────────────
-- Custom user-chosen spot. The TimecycleModifier below applies
-- a near-black indoor look so the Scene rig's lights dominate
-- regardless of surrounding geometry / weather / time.
-- The MP-Apartment high-rise IPL. We park the PLAYER ped inside a
-- room of this enclosed apartment while the multichar UI is open
-- — same trick qb-multicharacter uses. The interior is solid, has
-- no NPCs / weather / drowning / falling, so qb-ambulancejob can't
-- trigger a "respawn in X seconds" death loop while the player
-- waits in the UI. The preview ped stays at PedCoords below.
Config.Interior     = vector3(-779.0154, 326.1801, 196.0860)
Config.DefaultSpawn = vector4(-1035.71, -2731.87, 12.86, 0.0)     -- fallback world-spawn (existing characters)

-- Where freshly-created characters spawn the first time. Set nil
-- to reuse Config.DefaultSpawn. Useful for sending all newcomers
-- to a tutorial / starter beach / immigration office.
Config.NewCharacterSpawn = vector4(-1037.11, -2736.96, 20.17, 323.76)

Config.PedCoords    = vector4(-491.53, -624.59, 25.31, 331.00)    -- preview ped (scene anchor) — heading angled slightly to the left
Config.HiddenCoords = vector4(-779.0154, 326.1801, 196.0860, 91.0454)  -- player ped parked safely inside apartment IPL
Config.CamCoords    = vector4(-490.28, -621.74, 26.56, 331.67)    -- ~1.25m above ped, ~3m in front, rotated to match new heading

-- ── CAMERA FRAMING ──────────────────────────────────────────
Config.CameraFov       = 50.0   -- 35 = tight portrait, 50 = wide full body
Config.CamLookAtOffset = 0.85   -- vertical offset added to PedCoords.z for look-at:
                                --   0.0  = feet (will crop head)
                                --   0.65 = chest
                                --   0.85 = upper chest / shoulders (recommended)
                                --   1.6  = head

-- ── BACKGROUND DIMMING / FX OVERRIDE ────────────────────────
-- Applies a postFX timecycle. Also overrides automatic effects
-- like underwater blur / drugs / damage when needed.
-- Useful values:
--   'rply_motel_room_dark'  → near-black room (overrides underwater)
--   'phone_cam'             → dark + slight blur
--   'cinema'                → cinema lighting
--   'business'              → clean office lighting
--   ''                      → disabled
-- Sea floor needs an override to defeat GTA's automatic underwater
-- blue-tint + blur. 'rply_motel_room_dark' is a near-black indoor
-- look — perfect for the void backdrop AND it pre-empts the
-- underwater FX. Camera.lua applies it every frame.
Config.TimecycleModifier = 'rply_motel_room_dark'
Config.TimecycleStrength = 1.0

-- ── PREVIEW TIME & WEATHER LOCK ─────────────────────────────
-- While the multichar UI is open the player's local time is forced
-- to this. The default tunnel uses overhead lights that are tied to
-- time of day, so we lock to midnight to keep them lit.
-- Set PreviewHour to nil to disable the time lock entirely.
-- Set PreviewWeather to '' to leave weather alone.
Config.PreviewHour    = 0    -- 0 = midnight (lights on)
Config.PreviewMinute  = 0
Config.PreviewWeather = ''

Config.HideHud     = true   -- hide vanilla HUD + minimap while UI is open
Config.FadeInTime  = 800
Config.FadeOutTime = 800


-- ════════════════════════════════════════════════════════════════
--  SCENE  —  Forensic / classified-photoshoot booth
-- ════════════════════════════════════════════════════════════════
-- A minimalist studio rig built around the preview ped:
--   • props: optional set-dressing spawned around PedCoords
--   • lights: 3-point studio (key / fill / rim) drawn each frame
--   • ground ring: pulsing accent disc under the ped
--   • particle: subtle ambient glow
--
-- All offsets are relative to Config.PedCoords. Disable with
-- Config.Scene.enabled = false to fall back to the bare tunnel.
Config.Scene = {
    enabled = true,

    -- Optional manual ground Z. If set, the scene skips its own
    -- GetGroundZFor_3dCoord probe and uses this exact value to
    -- anchor lights / markers / props. Use this when the auto-probe
    -- snaps to the wrong layer (e.g. a tunnel beneath the road).
    -- Leave nil to auto-probe.
    --   Example: groundZOverride = 24.95,
    groundZOverride = nil,

    -- Set-dressing props. Models must exist in base game (no streams).
    -- Each entry: model + offset (rel. to PedCoords) + rotation (deg)
    -- Leave empty {} for a pure-light setup with no physical props.
    props = {
        -- backdrop screen behind ped (~3m back, slightly raised)
        { model = 'v_corp_blue_screen',  offset = vec3( 0.00, -2.40,  0.00), rot = vec3(0.0, 0.0,   0.0) },
        -- two studio softboxes flanking the ped
        { model = 'prop_studio_light_02', offset = vec3(-1.80,  0.30,  0.00), rot = vec3(0.0, 0.0,  60.0) },
        { model = 'prop_studio_light_02', offset = vec3( 1.80,  0.30,  0.00), rot = vec3(0.0, 0.0, -60.0) },
        -- tripod camera prop in front (set dressing — non-functional)
        { model = 'prop_tripod_01',       offset = vec3( 0.00,  2.20,  0.00), rot = vec3(0.0, 0.0, 180.0) },
    },

    -- 3-point lighting rig. Color may be:
    --   { r=, g=, b= }  → fixed RGB
    --   'theme'         → resolves to active theme primary
    --   'theme_alt'     → resolves to active theme secondary
    lights = {
        -- KEY · warm 3200K from above-front (matches "LIGHT · KEY 3200K" in UI)
        { offset = vec3( 0.30,  1.20,  2.40), color = { r = 255, g = 220, b = 180 }, range = 5.5, intensity = 9.0, pulse = 0.0 },
        -- FILL · cool dim from opposite side, lifts shadows
        { offset = vec3(-1.20,  0.40,  1.80), color = { r = 180, g = 200, b = 230 }, range = 4.0, intensity = 3.5, pulse = 0.0 },
        -- RIM · theme-colored from behind, separates ped from backdrop
        { offset = vec3( 0.00, -1.40,  1.90), color = 'theme',                       range = 4.5, intensity = 6.5, pulse = 0.20 },
        -- GROUND BOUNCE · subtle floor tint in theme color
        { offset = vec3( 0.00,  0.00,  0.10), color = 'theme_alt',                   range = 2.5, intensity = 2.0, pulse = 0.15 },
    },

    -- Pulsing accent disc under the ped (matches the red ellipse in the UI mock).
    groundRing = {
        enabled   = true,
        offset    = vec3(0.0, 0.0, 0.02),  -- relative to actual ground beneath ped
        scale     = vec3(1.6, 1.6, 0.3),   -- x/y radius, z thickness
        marker    = 25,                    -- 25 = thin ring (MARKER_RING)
        rotate    = true,                  -- slowly spins
        rotSpeed  = 12.0,                  -- deg/sec
        pulse     = 0.25,                  -- alpha breathe amplitude (0..1)
        baseAlpha = 140,                   -- 0..255
    },

    -- Glossy floor disc UNDER the ring — fakes a wet/polished studio
    -- floor reflection. Larger and dimmer than the ring.
    glossDisc = {
        enabled   = true,
        offset    = vec3(0.0, 0.0, 0.01),
        scale     = vec3(4.0, 4.0, 0.05),
        marker    = 1,                     -- 1 = MARKER_CYLINDER (we use thin Z)
        baseAlpha = 30,                    -- subtle
    },

    -- Slowly orbiting accent spot — extra dynamism around the ped.
    -- Lights up surfaces as it sweeps; renders behind the rim light.
    orbitSpot = {
        enabled   = true,
        radius    = 3.5,                   -- horizontal distance from ped
        height    = 2.6,                   -- vertical offset above ped feet
        speed     = 35.0,                  -- deg/sec
        color     = 'theme',               -- theme-driven
        range     = 4.0,
        intensity = 5.5,
    },

    -- Animated light streaks behind the ped — thin vertical beams
    -- that fall top-to-bottom on a loop, staggered so they don't
    -- move in sync. Sits in ped-local "behind" space (opposite of
    -- the ped's facing direction) so it's always visible to camera.
    streaks = {
        enabled       = true,
        count         = 7,             -- number of streaks
        backOffset    = 4.0,           -- meters behind ped
        spread        = 7.0,           -- width across (perpendicular to ped facing)
        topZ          = 4.5,           -- top of fall (above ground)
        bottomZ       = -0.3,          -- bottom (slightly under floor — fades out)
        length        = 1.6,           -- vertical streak length
        thickness     = 0.05,          -- streak diameter (very thin)
        cycleDuration = 3500,          -- ms per full fall (lower = faster)
        color         = 'theme',       -- theme | theme_alt | { r=, g=, b= }
        alpha         = 220,           -- 0..255
    },

    -- Periodic photo-studio shutter flash — bright instant-pop above ped.
    -- Mirrors the "PHOTO MODE" hint in the UI.
    cameraFlash = {
        enabled    = true,
        offset     = vec3(0.0, 1.5, 2.6),  -- in front of + above ped
        color      = { r = 255, g = 245, b = 220 },  -- daylight white
        range      = 8.0,
        peakIntensity = 25.0,              -- punch
        duration   = 120,                  -- ms hold (full bright)
        decay      = 250,                  -- ms fade tail
        intervalMin = 8000,                -- ms between flashes (random in range)
        intervalMax = 18000,
    },

    -- Set to nil / remove to disable
    particle = nil,
}

-- Color themes — only RIM + GROUND change between presets, KEY stays warm.
-- Add your own keys; selectable at runtime via NUI 'setTheme' callback.
Config.Themes = {
    crimson = {
        label     = 'CRIMSON',
        primary   = { r = 255, g =  35, b =  60 },
        secondary = { r = 110, g =   0, b =  20 },
    },
    arctic = {
        label     = 'ARCTIC',
        primary   = { r =  40, g = 180, b = 255 },
        secondary = { r =   0, g =  60, b = 110 },
    },
    toxic = {
        label     = 'TOXIC',
        primary   = { r = 180, g = 220, b =  60 },
        secondary = { r =  60, g =  90, b =   0 },
    },
}

Config.ActiveTheme = 'crimson'  -- default theme on UI open
```

{% endtab %}

{% tab title="ESX" %}

```lua
-- ════════════════════════════════════════════════════════════════
--  WORLD / CAMERA / PED PREVIEW
-- ════════════════════════════════════════════════════════════════
-- ── SPAWN ROUTING ──────────────────────────────────────────
-- After Login, where does the player end up?
--   'spawnSelector' → triggers feron_spawnSelector:open.
--                     Spawn UI lets the player pick a location.
--   'lastLocation'  → teleport directly to the user row's saved position.
--   'custom'        → invokes Config.OnCustomSpawn (see below). Use
--                     this to integrate any spawn selector
--                     (vms_spawnselector, esx_starting_apartments,
--                     your own UI).
--   'auto'          → detect feron_spawnSelector / Config.OnCustomSpawn
--                     and pick the most appropriate flow.
--
-- NOTE: QBCore-specific routes (qb-apartments, qb-spawn) are not
-- available on the ESX edition. To integrate an ESX apartment
-- script, route through 'custom' and trigger your script there.
Config.SpawnFlow = 'auto'

-- Custom spawn handler — fired when SpawnFlow resolves to 'custom'.
-- Receives source + charKey + last-known position + identity info.
-- Trigger your spawn selector / cutscene here.
Config.OnCustomSpawn = nil
-- Example (esx_starting_apartments):
-- Config.OnCustomSpawn = function(src, charKey, position, identity)
--     TriggerClientEvent('esx_starting_apartments:openMenu', src)
-- end

-- ── SPAWN SELECTOR INTEGRATION ─────────────────────────────
-- The three settings below let you swap feron_spawnSelector out
-- for another spawn-picker resource (vms_spawnselector, your own
-- UI, etc.) WITHOUT forking. Defaults point at feron's own — if
-- you're shipping with feron_spawnSelector, leave them alone.

-- 1. Resource name `ResolveSpawnFlow()` checks via GetResourceState
-- to decide whether to use the 'spawnSelector' flow vs.
-- 'lastLocation' / 'custom'. Set to your spawn picker's resource
-- name. Leave empty/nil to force-disable the spawnSelector flow
-- even if a feron_spawnSelector folder exists on disk — useful
-- when buying both but choosing to delegate via OnCustomSpawn.
Config.SpawnSelectorResource = 'feron_spawnSelector'

-- 2. Client event the multichar fires to ASK the spawn picker
-- to open its UI. Fired in two places:
--   * server/main.lua's SelectCharacter → TriggerClientEvent
--     (select / relog flow)
--   * client/main.lua's FinalizeFirstSpawn (after appearance
--     editor closes on new-character creation)
-- Your picker must register:
--   RegisterNetEvent(Config.SpawnSelectorOpenEvent, function(data) ... end)
Config.SpawnSelectorOpenEvent = 'feron_spawnSelector:client:openUI'

-- 3. Client event YOUR spawn picker emits once the player is
-- actually placed in the world (faded in, teleport done, ped
-- visible). Listened to so the multichar can:
--   * restore minimap / HUD overlays / voice bubble / routing bucket
--   * fire esx:onPlayerSpawn (local) + esx:restoreLoadout so HUD
--     scripts wake at the right moment
-- Set to your picker's equivalent:
--   Config.SpawnFinishEvent = 'yourspawn:client:spawned'
-- Your picker must call (CLIENT, AFTER placement):
--   TriggerEvent(Config.SpawnFinishEvent)
--
-- Leave nil to skip the deferral (HUDs restore immediately when
-- FinalizeSpawn returns). Use this if your selector has no
-- finished signal; trade-off is a brief HUD flash during selection.
Config.SpawnFinishEvent = 'feron_spawnSelector:client:spawnFinished'

-- ── PREVIEW LOCATION ────────────────────────────────────────
-- Custom user-chosen spot. The TimecycleModifier below applies
-- a near-black indoor look so the Scene rig's lights dominate
-- regardless of surrounding geometry / weather / time.
-- The MP-Apartment high-rise IPL. We park the PLAYER ped inside a
-- room of this enclosed apartment while the multichar UI is open
-- — same trick qb-multicharacter uses. The interior is solid, has
-- no NPCs / weather / drowning / falling, so qb-ambulancejob can't
-- trigger a "respawn in X seconds" death loop while the player
-- waits in the UI. The preview ped stays at PedCoords below.
Config.Interior     = vector3(-779.0154, 326.1801, 196.0860)
Config.DefaultSpawn = vector4(-1035.71, -2731.87, 12.86, 0.0)     -- fallback world-spawn (existing characters)

-- Where freshly-created characters spawn the first time. Set nil
-- to reuse Config.DefaultSpawn. Useful for sending all newcomers
-- to a tutorial / starter beach / immigration office.
Config.NewCharacterSpawn = vector4(-1037.11, -2736.96, 20.17, 323.76)

Config.PedCoords    = vector4(-491.53, -624.59, 25.31, 331.00)    -- preview ped (scene anchor) — heading angled slightly to the left
Config.HiddenCoords = vector4(-779.0154, 326.1801, 196.0860, 91.0454)  -- player ped parked safely inside apartment IPL
Config.CamCoords    = vector4(-490.28, -621.74, 26.56, 331.67)    -- ~1.25m above ped, ~3m in front, rotated to match new heading

-- ── CAMERA FRAMING ──────────────────────────────────────────
Config.CameraFov       = 50.0   -- 35 = tight portrait, 50 = wide full body
Config.CamLookAtOffset = 0.85   -- vertical offset added to PedCoords.z for look-at:
                                --   0.0  = feet (will crop head)
                                --   0.65 = chest
                                --   0.85 = upper chest / shoulders (recommended)
                                --   1.6  = head

-- ── BACKGROUND DIMMING / FX OVERRIDE ────────────────────────
-- Applies a postFX timecycle. Also overrides automatic effects
-- like underwater blur / drugs / damage when needed.
-- Useful values:
--   'rply_motel_room_dark'  → near-black room (overrides underwater)
--   'phone_cam'             → dark + slight blur
--   'cinema'                → cinema lighting
--   'business'              → clean office lighting
--   ''                      → disabled
-- Sea floor needs an override to defeat GTA's automatic underwater
-- blue-tint + blur. 'rply_motel_room_dark' is a near-black indoor
-- look — perfect for the void backdrop AND it pre-empts the
-- underwater FX. Camera.lua applies it every frame.
Config.TimecycleModifier = 'rply_motel_room_dark'
Config.TimecycleStrength = 1.0

-- ── PREVIEW TIME & WEATHER LOCK ─────────────────────────────
-- While the multichar UI is open the player's local time is forced
-- to this. The default tunnel uses overhead lights that are tied to
-- time of day, so we lock to midnight to keep them lit.
-- Set PreviewHour to nil to disable the time lock entirely.
-- Set PreviewWeather to '' to leave weather alone.
Config.PreviewHour    = 0    -- 0 = midnight (lights on)
Config.PreviewMinute  = 0
Config.PreviewWeather = ''

Config.HideHud     = true   -- hide vanilla HUD + minimap while UI is open
Config.FadeInTime  = 800
Config.FadeOutTime = 800


-- ════════════════════════════════════════════════════════════════
--  SCENE  —  Forensic / classified-photoshoot booth
-- ════════════════════════════════════════════════════════════════
-- A minimalist studio rig built around the preview ped:
--   • props: optional set-dressing spawned around PedCoords
--   • lights: 3-point studio (key / fill / rim) drawn each frame
--   • ground ring: pulsing accent disc under the ped
--   • particle: subtle ambient glow
--
-- All offsets are relative to Config.PedCoords. Disable with
-- Config.Scene.enabled = false to fall back to the bare tunnel.
Config.Scene = {
    enabled = true,

    -- Optional manual ground Z. If set, the scene skips its own
    -- GetGroundZFor_3dCoord probe and uses this exact value to
    -- anchor lights / markers / props. Use this when the auto-probe
    -- snaps to the wrong layer (e.g. a tunnel beneath the road).
    -- Leave nil to auto-probe.
    --   Example: groundZOverride = 24.95,
    groundZOverride = nil,

    -- Set-dressing props. Models must exist in base game (no streams).
    -- Each entry: model + offset (rel. to PedCoords) + rotation (deg)
    -- Leave empty {} for a pure-light setup with no physical props.
    props = {
        -- backdrop screen behind ped (~3m back, slightly raised)
        { model = 'v_corp_blue_screen',  offset = vec3( 0.00, -2.40,  0.00), rot = vec3(0.0, 0.0,   0.0) },
        -- two studio softboxes flanking the ped
        { model = 'prop_studio_light_02', offset = vec3(-1.80,  0.30,  0.00), rot = vec3(0.0, 0.0,  60.0) },
        { model = 'prop_studio_light_02', offset = vec3( 1.80,  0.30,  0.00), rot = vec3(0.0, 0.0, -60.0) },
        -- tripod camera prop in front (set dressing — non-functional)
        { model = 'prop_tripod_01',       offset = vec3( 0.00,  2.20,  0.00), rot = vec3(0.0, 0.0, 180.0) },
    },

    -- 3-point lighting rig. Color may be:
    --   { r=, g=, b= }  → fixed RGB
    --   'theme'         → resolves to active theme primary
    --   'theme_alt'     → resolves to active theme secondary
    lights = {
        -- KEY · warm 3200K from above-front (matches "LIGHT · KEY 3200K" in UI)
        { offset = vec3( 0.30,  1.20,  2.40), color = { r = 255, g = 220, b = 180 }, range = 5.5, intensity = 9.0, pulse = 0.0 },
        -- FILL · cool dim from opposite side, lifts shadows
        { offset = vec3(-1.20,  0.40,  1.80), color = { r = 180, g = 200, b = 230 }, range = 4.0, intensity = 3.5, pulse = 0.0 },
        -- RIM · theme-colored from behind, separates ped from backdrop
        { offset = vec3( 0.00, -1.40,  1.90), color = 'theme',                       range = 4.5, intensity = 6.5, pulse = 0.20 },
        -- GROUND BOUNCE · subtle floor tint in theme color
        { offset = vec3( 0.00,  0.00,  0.10), color = 'theme_alt',                   range = 2.5, intensity = 2.0, pulse = 0.15 },
    },

    -- Pulsing accent disc under the ped (matches the red ellipse in the UI mock).
    groundRing = {
        enabled   = true,
        offset    = vec3(0.0, 0.0, 0.02),  -- relative to actual ground beneath ped
        scale     = vec3(1.6, 1.6, 0.3),   -- x/y radius, z thickness
        marker    = 25,                    -- 25 = thin ring (MARKER_RING)
        rotate    = true,                  -- slowly spins
        rotSpeed  = 12.0,                  -- deg/sec
        pulse     = 0.25,                  -- alpha breathe amplitude (0..1)
        baseAlpha = 140,                   -- 0..255
    },

    -- Glossy floor disc UNDER the ring — fakes a wet/polished studio
    -- floor reflection. Larger and dimmer than the ring.
    glossDisc = {
        enabled   = true,
        offset    = vec3(0.0, 0.0, 0.01),
        scale     = vec3(4.0, 4.0, 0.05),
        marker    = 1,                     -- 1 = MARKER_CYLINDER (we use thin Z)
        baseAlpha = 30,                    -- subtle
    },

    -- Slowly orbiting accent spot — extra dynamism around the ped.
    -- Lights up surfaces as it sweeps; renders behind the rim light.
    orbitSpot = {
        enabled   = true,
        radius    = 3.5,                   -- horizontal distance from ped
        height    = 2.6,                   -- vertical offset above ped feet
        speed     = 35.0,                  -- deg/sec
        color     = 'theme',               -- theme-driven
        range     = 4.0,
        intensity = 5.5,
    },

    -- Animated light streaks behind the ped — thin vertical beams
    -- that fall top-to-bottom on a loop, staggered so they don't
    -- move in sync. Sits in ped-local "behind" space (opposite of
    -- the ped's facing direction) so it's always visible to camera.
    streaks = {
        enabled       = true,
        count         = 7,             -- number of streaks
        backOffset    = 4.0,           -- meters behind ped
        spread        = 7.0,           -- width across (perpendicular to ped facing)
        topZ          = 4.5,           -- top of fall (above ground)
        bottomZ       = -0.3,          -- bottom (slightly under floor — fades out)
        length        = 1.6,           -- vertical streak length
        thickness     = 0.05,          -- streak diameter (very thin)
        cycleDuration = 3500,          -- ms per full fall (lower = faster)
        color         = 'theme',       -- theme | theme_alt | { r=, g=, b= }
        alpha         = 220,           -- 0..255
    },

    -- Periodic photo-studio shutter flash — bright instant-pop above ped.
    -- Mirrors the "PHOTO MODE" hint in the UI.
    cameraFlash = {
        enabled    = true,
        offset     = vec3(0.0, 1.5, 2.6),  -- in front of + above ped
        color      = { r = 255, g = 245, b = 220 },  -- daylight white
        range      = 8.0,
        peakIntensity = 25.0,              -- punch
        duration   = 120,                  -- ms hold (full bright)
        decay      = 250,                  -- ms fade tail
        intervalMin = 8000,                -- ms between flashes (random in range)
        intervalMax = 18000,
    },

    -- Set to nil / remove to disable
    particle = nil,
}

-- Color themes — only RIM + GROUND change between presets, KEY stays warm.
-- Add your own keys; selectable at runtime via NUI 'setTheme' callback.
Config.Themes = {
    crimson = {
        label     = 'CRIMSON',
        primary   = { r = 255, g =  35, b =  60 },
        secondary = { r = 110, g =   0, b =  20 },
    },
    arctic = {
        label     = 'ARCTIC',
        primary   = { r =  40, g = 180, b = 255 },
        secondary = { r =   0, g =  60, b = 110 },
    },
    toxic = {
        label     = 'TOXIC',
        primary   = { r = 180, g = 220, b =  60 },
        secondary = { r =  60, g =  90, b =   0 },
    },
}

Config.ActiveTheme = 'crimson'  -- default theme on UI open
```

{% endtab %}
{% endtabs %}


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://feron-scripts.gitbook.io/welcome/scripts/feron-multicharacter/config/world-scene.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
