Quick Start

By the end of this page you have a settings screen with a couple of options that persist per player - no game-code binding, no fields added anywhere. Making an option actually change the game comes next (How-To: Bind a Setting to Game Code).

Prerequisites
CrimsonSettings is installed, and you have a UI layer to push a screen to - your own layout, or any CommonUI activatable-widget stack (step 6 shows one).

Tick Show Plugin Content in the Content Browser's Settings menu - plugin assets are hidden until you do, and several pages here point at shipped ones.

1. Enable the plugin

Open Edit -> Plugins, type Crimson, tick CrimsonSettings, and restart when prompted. For a Blueprint project that's the whole install.

Verify
CrimsonSettings shows as enabled in the Plugins window and the editor restarts without errors.

2. Register the GameUserSettings class

This step is not optional and there is no in-editor equivalent - it is one line of config, and without it the plugin asserts. Add to Config/DefaultEngine.ini, then restart the editor:

ini
[/Script/Engine.Engine]
GameUserSettingsClassName=/Script/CrimsonSettings.CrimsonSettingsLocal

The engine allocates exactly one UGameUserSettings object and takes its class from this value. UCrimsonSettingsLocal::Get() is a CastChecked over GEngine->GetGameUserSettings(), so with a plain UGameUserSettings allocated the cast asserts - and every shipped video, audio, gamepad and mouse row calls Get(). It is the same shape of registration a GAS project makes with AbilitySystemGlobalsClassName: one ClassName line under [/Script/Engine.Engine].

Already subclassing it?
Point the line at your class instead - the cast is to the Crimson base, so any subclass satisfies it: GameUserSettingsClassName=/Script/MyGame.MyGameUserSettings.
Verify
Restart, then open any screen that reaches UCrimsonSettingsLocal::Get(). A missing line shows up as an assert inside GetGameUserSettings, not as a log warning - so if nothing asserts, it is registered.

3. Create a settings data asset

Right-click in the Content Browser -> Miscellaneous -> Data Asset -> CrimsonSettingsDataAsset. Add a Section (e.g. Gameplay), then add Settings entries. For each entry set the Type, DevName, DisplayName, and - to persist it with no code - tick Persist To Shared Store (leave StorageKey empty to reuse DevName).

Unrelated fields collapse
Type-specific fields hide when they don't apply: a Scalar shows range/step/default; a Discrete shows options/default index; an Action shows its button text. DevName must be unique within a registry.
Verify
The asset lists your section with its entries, and each entry shows Persist To Shared Store ticked under the Storage category.

4. Create a registry

The registry turns the asset into live settings. Make a Blueprint child of UCrimsonSettingRegistry, and in one of the category hooks call Populate From Data Asset with your asset.

In BP_GameplaySettingsRegistry, open My Blueprint -> Functions -> Override and pick K2_RegisterGameplaySettings. Wire the event it drops in: K2_RegisterGameplaySettings -> Populate From Data Asset (Data Asset = DA_GameplaySettings, Parent Collection = empty). Populate From Data Asset is a Settings | Registry node on the registry itself, so its target pin is Self.

The four override events - K2_RegisterVideoSettings, K2_RegisterAudioSettings, K2_RegisterInputSettings and K2_RegisterGameplaySettings - all fire in that order during initialization and are otherwise interchangeable. Pick the one that matches what your asset holds; nothing breaks if you register everything from one of them.

Verify
Populate From Data Asset accepts your asset with no warnings in the Output Log.

5. Create the settings screen

Make a Blueprint widget child of UCrimsonSettingScreen. Add a UCrimsonSettingPanel named exactly `Settings_Panel` (a bind-widget). Override `Create Registry` to return your registry, initialized for the owning local player.

In the Designer, add the one child the base class binds by name. Get this name wrong and the Blueprint refuses to compile - BindWidget is a hard requirement, not a convention:

Widget className (exact)Why
UCrimsonSettingPanelSettings_PanelThe screen hands it the registry and it renders every row. A BindWidget, so it is required and the name must match character for character.

Then in the Graph, use My Blueprint -> Functions -> Override and pick Create Registry. Wire Create Registry -> Construct Object from Class (Class = BP_GameplaySettingsRegistry, Outer = Get Owning Local Player) -> Initialize (In Local Player = the same Get Owning Local Player), then feed the constructed registry into the Return Node.

Do not skip Initialize
Initialize is what fires the K2_Register... events and so builds every row. A registry you construct and return without it comes back empty - the screen renders with no settings and nothing errors. A second call is rejected, so calling it once here is safe.
Verify
The widget compiles with Settings_Panel bound (no "BindWidget" error) and Create Registry returns your registry class.

6. Push the screen

Push the screen onto a UI layer from a menu button (or BeginPlay for a test).

On the menu button: OnClicked -> Get Primary Game Layout (Player Controller = Get Owning Player) -> Get Layer Widget (Layer Name = your menu layer tag, e.g. UI.Layer.Menu) -> Push Widget (Activatable Widget Class = WBP_SettingsScreen).

Get Primary Game Layout and Get Layer Widget stand for your own layout's accessors (a Lyra-style primary layout, for example); Push Widget is CommonUI's own node on the activatable-widget container. Using a different layout? Add the widget however that layout adds widgets - the screen is an ordinary UCommonActivatableWidget.

Verify
The screen lists your options. Change them, click Apply, close and reopen the game - the values are still there. They persist per player because you ticked Persist To Shared Store.
What's next
Skip authoring entirely and take the shipped menu (How-To: Use the Ready-Made Collections), make an option do something (How-To: Bind a Setting to Game Code), expose another plugin's options with no dependency (How-To: Expose Another Plugin's Settings), or add polish (How-To: Presets & Profiles, How-To: Live Preview & Confirmation).