# Onboarding (/docs/orbit-studios-resources/orbit-dynamichud/onboarding)



# Onboarding [#onboarding]

Orbit Dynamic HUD 2.0 can start onboarding automatically for a new player, wait for another resource to trigger it, or disable it completely. Completion is remembered by the NUI, while the backend configuration remains authoritative over whether onboarding is available.

## Configuration [#configuration]

Use the object form in `shared/config.lua`:

```lua title="resources/[orbit]/orbit-dynamichud-v2/shared/config.lua"
Config.Onboarding = {
    enabled = true,
    trigger = "auto", -- "auto" or "manual"
}

Config.Commands = {
    controlpanel = { enabled = true },
    customize = { enabled = true },
    music = { enabled = true },
    carcontrol = { enabled = true },
    settings = { enabled = true },
    settingsshare = { enabled = true },
    editmode = { enabled = true },
    restarthud = { enabled = true },
    engine = { enabled = true },
    onboarding = { enabled = true },
}
```

| Setting                              | Value      | Effect                                                                                                         |
| ------------------------------------ | ---------- | -------------------------------------------------------------------------------------------------------------- |
| `enabled`                            | `true`     | Allow onboarding to start through the configured mode, public event, export, and optionally its command.       |
| `enabled`                            | `false`    | Disable onboarding starts completely. Public start calls remain safe no-ops and the command is not registered. |
| `trigger`                            | `"auto"`   | Show onboarding automatically when an incomplete first run is ready.                                           |
| `trigger`                            | `"manual"` | Keep an incomplete first run hidden until another resource triggers it.                                        |
| `Config.Commands.onboarding.enabled` | `true`     | Register the localized `/onboarding` command.                                                                  |
| `Config.Commands.onboarding.enabled` | `false`    | Disable only the command. The public event remains available while onboarding itself is enabled.               |

The legacy boolean form is still accepted for compatibility: `true` means enabled with automatic triggering, while `false` disables onboarding. The object form is recommended because it exposes the trigger mode explicitly.

<Callout type="warn" title="Settings lock takes priority">
  `Config.SettingsLocked = true` blocks onboarding regardless of its own configuration. This prevents onboarding from replacing server-enforced defaults.
</Callout>

## Automatic mode [#automatic-mode]

```lua title="resources/[orbit]/orbit-dynamichud-v2/shared/config.lua"
Config.Onboarding = {
    enabled = true,
    trigger = "auto",
}
```

Automatic mode is appropriate when DynamicHUD can own the first-run flow. For an incomplete first run, the client waits until:

* normalized player data reports that the player is logged in
* another NUI is not holding focus
* the built-in Text UI is not already showing a prompt owned by another resource

Once those conditions are met, a localized Text UI notice counts down from five seconds. Only an uninterrupted five-second availability window counts. If another NUI takes focus or another Text UI prompt appears, DynamicHUD hides only its own notice, resets the timer, and waits. The notice and full five-second countdown start again when the interface is free.

Translate the notice with the `onboarding_countdown` key in every enabled `locales/*.json` file. Keep the `%d` placeholder in the translated value; it is replaced with the current remaining second.

The countdown cannot mature in a character selector because it starts only after the normalized logged-in state becomes true. The availability watcher runs only for the initial incomplete automatic flow. Opening onboarding later through the command, event, or export bypasses both the watcher and countdown and requests focus directly.

Players who already completed onboarding do not see it automatically again.

## Manual mode [#manual-mode]

```lua title="resources/[orbit]/orbit-dynamichud-v2/shared/config.lua"
Config.Onboarding = {
    enabled = true,
    trigger = "manual",
}
```

Manual mode keeps first-run onboarding dormant until your login, character, spawn, or tutorial resource decides the player is ready. Trigger it after the player has loaded and the DynamicHUD client resource has initialized.

### Trigger from a client resource [#trigger-from-a-client-resource]

```lua title="resources/[custom]/client/main.lua"
RegisterNetEvent("my-intro:client:finished", function()
    TriggerEvent("orbit-dynamichud:client:openOnboarding")
end)
```

The equivalent client export returns whether the request passed the local configuration and login guards:

```lua title="resources/[custom]/client/main.lua"
local requested = exports['orbit-dynamichud-v2']:startOnboarding()
```

### Trigger from a server resource [#trigger-from-a-server-resource]

```lua title="resources/[custom]/server/main.lua"
local function finishPlayerSetup(playerSource)
    TriggerClientEvent(
        "orbit-dynamichud:client:openOnboarding",
        playerSource
    )
end
```

The event is intentionally non-forcing. It opens onboarding only when that client still has an incomplete onboarding state. Triggering it for somebody who already finished onboarding does nothing, so a server event cannot overwrite a completed player's choice.

Use manual mode when:

* a multicharacter resource must finish character selection first
* identity, apartment, or spawn selection owns the initial focus
* a server tutorial or cutscene should finish before HUD configuration
* the player starts in a routing bucket and should configure the HUD after leaving it
* framework data is not ready at the moment the HUD resource starts

Avoid triggering the event every tick or on every respawn. Call it once at the meaningful completion point in your flow. The completed-state check makes duplicate calls harmless, but they are still unnecessary work.

## Command and event behavior [#command-and-event-behavior]

| Entry point                              | Reopens completed onboarding | Starts automatic watcher | Requirements                                                              |
| ---------------------------------------- | ---------------------------- | ------------------------ | ------------------------------------------------------------------------- |
| Initial automatic run                    | No                           | Yes                      | `enabled = true`, `trigger = "auto"`, incomplete state, settings unlocked |
| `orbit-dynamichud:client:openOnboarding` | No                           | No                       | `enabled = true`, incomplete state, settings unlocked                     |
| `startOnboarding` export                 | No                           | No                       | `enabled = true`, incomplete state, player logged in, settings unlocked   |
| `/onboarding`                            | Yes                          | No                       | onboarding enabled, command enabled, settings unlocked                    |

The localized `/onboarding` command is the support and testing path. It deliberately forces the flow open even after completion, but it does not change automatic/manual mode and does not create a background onboarding thread.

## Query or close onboarding [#query-or-close-onboarding]

Read the current state and close the flow from a client resource with exports:

```lua title="resources/[custom]/client/main.lua"
local onboardingState = exports['orbit-dynamichud-v2']:getOnboardingState()

if onboardingState then
    exports['orbit-dynamichud-v2']:closeOnboarding()
end
```

The event form is suitable for both client and targeted server integrations:

```lua title="resources/[custom]/client/main.lua"
TriggerEvent('orbit-dynamichud:client:closeOnboarding')
```

```lua title="resources/[custom]/server/main.lua"
TriggerClientEvent(
    'orbit-dynamichud:client:closeOnboarding',
    playerSource
)
```

Closing is idempotent. It resets the onboarding flow in the NUI and releases focus only when onboarding is the interface using it. Use `getHudVisibility()` when another client resource also needs the gameplay HUD's current effective visibility.

## Recommended manual integration [#recommended-manual-integration]

1. Set `Config.Onboarding.trigger = "manual"`.
2. Keep `Config.Onboarding.enabled = true`.
3. Decide which existing resource owns the last step before normal gameplay.
4. Trigger `orbit-dynamichud:client:openOnboarding` once after that step and after player data is loaded.
5. Keep `/onboarding` enabled while testing, then decide whether players should retain that recovery command.
6. Test both a fresh client state and a client that already completed onboarding.

If the manual event does not open anything, verify that onboarding is enabled, settings are not locked, the player has not already completed onboarding, and the event is fired after `orbit-dynamichud-v2` starts. Use `/onboarding` to distinguish a completed-state no-op from a configuration or focus problem.
