Overview
player_ui is the per-player UI canvas that lives behind every player's screen. It is not a placed device — you obtain it at runtime by calling GetPlayerUI(Player) from the /UnrealEngine.com/Temporary/UI module. Once you have the canvas you can:
AddWidget(Widget)— push anywidget(text blocks, overlays, canvases) onto the player's screen.AddWidget(Widget, Slot)— same, but with aplayer_ui_slotfor z-order and alignment control.RemoveWidget(Widget)— pull a widget back off the screen.SetFocus(Widget)— move input focus to a specific focusable widget.
The classic use-case: a player walks onto a pressure plate on the dock → a cel-shaded location title fades in just for them → they walk off → it disappears. Because the UI is per-player, every crew member on your pirate island can see a different widget at the same time.
API Reference
player_ui
The main interface for adding and removing
widgets to a player's UI.
Full public surface, resolved verbatim from the live Epic digest (UnrealEngine.digest.verse).
player_ui<native><public> := class<final><epic_internal>:
player
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse). Inherited members are merged from agent.
player<native><public> := class<unique><persistent><module_scoped_var_weak_map_key><epic_internal>(agent):
trigger_device
Used to relay events to other linked devices.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from trigger_base_device.
trigger_device<public> := class<concrete><final>(trigger_base_device):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
TriggeredEvent |
TriggeredEvent<public>:listenable(?agent) |
Signaled when an agent triggers this device. Sends the agent that used this device. Returns false if no agent triggered the action (ex: it was triggered through code). |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Trigger |
Trigger<public>(Agent:agent):void |
Triggers this device with Agent being passed as the agent that triggered the action. Use an agent reference when this device is setup to require one (for instance, you want to trigger the device only with a particular agent. |
Trigger |
Trigger<public>():void |
Triggers this device, causing it to activate its TriggeredEvent event. |
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
SetMaxTriggerCount |
SetMaxTriggerCount<public>(MaxCount:int):void |
Sets the maximum amount of times this device can trigger. * 0 can be used to indicate no limit on trigger count. * MaxCount is clamped between [0,20]. |
GetMaxTriggerCount |
GetMaxTriggerCount<public>()<transacts>:int |
Gets the maximum amount of times this device can trigger. * 0 indicates no limit on trigger count. |
GetTriggerCountRemaining |
GetTriggerCountRemaining<public>()<transacts>:int |
Returns the number of times that this device can still be triggered before hitting GetMaxTriggerCount. Returns 0 if GetMaxTriggerCount is unlimited. |
SetResetDelay |
SetResetDelay<public>(Time:float):void |
Sets the time (in seconds) after triggering, before the device can be triggered again (if MaxTrigger count allows). |
GetResetDelay |
GetResetDelay<public>()<transacts>:float |
Gets the time (in seconds) before the device can be triggered again (if MaxTrigger count allows). |
SetTransmitDelay |
SetTransmitDelay<public>(Time:float):void |
Sets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered. |
GetTransmitDelay |
GetTransmitDelay<public>()<transacts>:float |
Gets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered. |
Walkthrough
Scenario — Dock Arrival Banner
You have a sun-drenched pirate cove. A trigger_device sits at the end of the wooden dock. When a player steps on it, a cel-shaded "Welcome to Cove Hideout!" banner appears only for that player. A second trigger at the shore's edge removes it when they walk away.
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Fortnite.com/UI }
# Localisation helper — player_ui requires `message`, not raw strings
DockBannerText<localizes>(S : string) : message = "{S}"
dock_arrival_banner := class(creative_device):
# ── Placed devices (wire these up in UEFN) ──────────────────────────
# Trigger at the end of the dock — fires when a player steps on it
@editable
DockEntryTrigger : trigger_device = trigger_device{}
# Trigger at the shore edge — fires when a player walks away
@editable
DockExitTrigger : trigger_device = trigger_device{}
# ── Internal state ──────────────────────────────────────────────────
# We keep a reference to the widget so we can remove it later.
# In a real project you would use a per-player map; here we keep
# a single slot for clarity.
var BannerWidget : ?widget = false
# ── Lifecycle ───────────────────────────────────────────────────────
OnBegin<override>()<suspends> : void =
# Subscribe to both triggers
DockEntryTrigger.TriggeredEvent.Subscribe(OnPlayerArrivedAtDock)
DockExitTrigger.TriggeredEvent.Subscribe(OnPlayerLeftDock)
# Limit the exit trigger to fire once per entry so it stays in sync
DockExitTrigger.SetMaxTriggerCount(1)
DockExitTrigger.SetResetDelay(0.5)
# ── Event handlers ──────────────────────────────────────────────────
# Called when TriggeredEvent fires — the payload is ?agent
OnPlayerArrivedAtDock(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (P := player[A]):
ShowDockBanner(P)
OnPlayerLeftDock(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (P := player[A]):
HideDockBanner(P)
# ── UI helpers ──────────────────────────────────────────────────────
ShowDockBanner(P : player) : void =
# GetPlayerUI<decides> — must be inside an `if` to handle failure
if (UI := GetPlayerUI[P]):
# Build a simple text widget for the cel-shaded banner
Banner := text_block:
DefaultText := DockBannerText("⚓ Welcome to Cove Hideout!")
# AddWidget pushes it onto this player's private canvas
UI.AddWidget(Banner)
# Store so we can remove it later
set BannerWidget = option{Banner}
HideDockBanner(P : player) : void =
if (UI := GetPlayerUI[P]):
if (W := BannerWidget?):
# RemoveWidget pulls it back off the screen
UI.RemoveWidget(W)
set BannerWidget = false
Line-by-line explanation
| Lines | What's happening |
|---|---|
DockEntryTrigger, DockExitTrigger |
Two @editable trigger devices wired in UEFN. The entry trigger fires when a player steps onto the dock; the exit trigger fires when they walk back to shore. |
OnBegin |
Subscribes both triggers and configures the exit trigger to reset after 0.5 s so it can fire again next time. SetMaxTriggerCount(1) + SetResetDelay are real trigger_device methods. |
OnPlayerArrivedAtDock(MaybeAgent : ?agent) |
TriggeredEvent sends ?agent — always unwrap with if (A := MaybeAgent?) before use. Then cast to player with player[A]. |
GetPlayerUI[P] |
Failable (<decides>) — must live inside an if. Returns the player_ui canvas for that specific player. |
UI.AddWidget(Banner) |
Pushes the text block onto only this player's screen. Other players see nothing. |
UI.RemoveWidget(W) |
Cleanly removes the widget when the player walks away. |
Common patterns
Pattern 1 — One-shot splash with auto-dismiss using SetMaxTriggerCount
A clifftop trigger shows a "Treasure Found!" splash to the triggering player, then auto-removes it after a delay. The trigger is capped at one fire per reset cycle.
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
TreasureFoundText<localizes>(S : string) : message = "{S}"
treasure_splash_device := class(creative_device):
@editable
CliffTopTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
# Fire once, then reset after 10 seconds
CliffTopTrigger.SetMaxTriggerCount(1)
CliffTopTrigger.SetResetDelay(10.0)
CliffTopTrigger.TriggeredEvent.Subscribe(OnCliffReached)
OnCliffReached(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (P := player[A]):
if (UI := GetPlayerUI[P]):
Splash := text_block:
DefaultText := TreasureFoundText("💰 Treasure Found!")
UI.AddWidget(Splash)
# Auto-remove after 3 seconds
spawn { AutoRemove(UI, Splash) }
AutoRemove(UI : player_ui, W : widget)<suspends> : void =
Sleep(3.0)
UI.RemoveWidget(W)
Pattern 2 — Re-enable a trigger and check remaining count
A lagoon buoy trigger is disabled at start. A separate shore trigger enables it and logs how many fires remain, demonstrating Enable, Disable, GetTriggerCountRemaining, and GetMaxTriggerCount.
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
BuoyAlertText<localizes>(S : string) : message = "{S}"
lagoon_buoy_device := class(creative_device):
@editable
BuoyTrigger : trigger_device = trigger_device{}
@editable
ShoreTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
# Buoy starts disabled; shore trigger arms it
BuoyTrigger.Disable()
BuoyTrigger.SetMaxTriggerCount(3) # can fire 3 times total
ShoreTrigger.TriggeredEvent.Subscribe(OnShoreReached)
BuoyTrigger.TriggeredEvent.Subscribe(OnBuoyTriggered)
OnShoreReached(MaybeAgent : ?agent) : void =
BuoyTrigger.Enable() # arm the buoy
OnBuoyTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (P := player[A]):
Remaining := BuoyTrigger.GetTriggerCountRemaining()
Max := BuoyTrigger.GetMaxTriggerCount()
if (UI := GetPlayerUI[P]):
Alert := text_block:
DefaultText := BuoyAlertText("🔔 Buoy hit! Fires left: {Remaining}/{Max}")
UI.AddWidget(Alert)
spawn { AutoRemove(UI, Alert) }
AutoRemove(UI : player_ui, W : widget)<suspends> : void =
Sleep(2.0)
UI.RemoveWidget(W)
Pattern 3 — SetFocus on an interactive widget
A pirate ship trigger opens a cel-shaded choice overlay and focuses the first button so gamepad players can interact immediately.
using { /Fortnite.com/Devices }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
ChoicePromptText<localizes>(S : string) : message = "{S}"
ship_choice_device := class(creative_device):
@editable
ShipBoardingTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
ShipBoardingTrigger.TriggeredEvent.Subscribe(OnBoarded)
OnBoarded(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
if (P := player[A]):
if (UI := GetPlayerUI[P]):
# Build a focusable button widget
ChoiceBtn := button_loud:
DefaultText := ChoicePromptText("⚔ Board the ship?")
UI.AddWidget(ChoiceBtn)
# Move gamepad / keyboard focus to this button immediately
UI.SetFocus(ChoiceBtn)
spawn { AutoRemove(UI, ChoiceBtn) }
AutoRemove(UI : player_ui, W : widget)<suspends> : void =
Sleep(5.0)
UI.RemoveWidget(W)
Gotchas
1. GetPlayerUI is failable — always wrap in if
GetPlayerUI is marked <decides>, meaning it can fail (e.g. the player has already left the session). Never call it bare:
# ❌ WRONG — compile error, <decides> not handled
UI := GetPlayerUI(P)
# ✅ CORRECT
if (UI := GetPlayerUI[P]):
UI.AddWidget(MyWidget)
2. TriggeredEvent sends ?agent, not agent
The event payload is optional — the device can fire without a player (e.g. triggered from code). Always unwrap:
# ❌ Treating ?agent as agent crashes at compile time
OnFired(A : agent) : void = ...
# ✅ Correct handler signature + unwrap
OnFired(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?): ...
3. message ≠ string — use a <localizes> helper
text_block.DefaultText and similar widget fields require a message value, not a plain string. There is no StringToMessage function. Declare a thin localisation wrapper:
MyLabel<localizes>(S : string) : message = "{S}"
# Then use:
text_block{ DefaultText := MyLabel("Cove Hideout") }
4. player_ui is per-player — not global
Widgets you add via AddWidget are invisible to everyone else. If you want all players to see the same widget you must call AddWidget inside a loop over every player in the playspace.
5. Remove widgets you no longer need
Widgets are not automatically cleaned up when a player respawns or the round resets. Always call RemoveWidget (or track and remove on round-end) to avoid stale overlays piling up on the screen.
6. SetMaxTriggerCount clamps to [0, 20]
Passing a value outside this range is silently clamped. Use 0 to mean "unlimited". Check GetTriggerCountRemaining() returns 0 when unlimited — don't use it as a countdown in that case.