Live Widget State Binding with Verse
What you'll learn
- Building a live widget (a
slider_device'sWidget) and attaching it to each player'splayer_ui. - Correctly binding the fallible
GetPlayerUI[]call inside a failure context. - Pushing real-time updates with a coroutine loop and
Sleep. - Doing safe integer-to-float normalization WITHOUT the
%operator (error 3100) or fallible/.
How it works
Verse UI binding bridges your simulation state to what each player sees on screen. The key API is GetPlayerUI[Player] — it is <decides> (fallible) because a player may not have an associated player_ui yet, so we must call it with [] inside an if condition and bind the result: if (UI := GetPlayerUI[Player]):.
Once we hold a player_ui, we call UI.AddWidget(...) and hand it our device's Widget. We use a slider_device's .Widget slot as our concrete on-screen element. From there a coroutine loop reads a mutable int metric, normalizes it into the slider's 0.0–1.0 range, and calls SetValue(...) every quarter second.
Why the original failed (error 3100): Verse has no % operator and integer / is fallible. We avoid both by converting to float first (CurrentCurrency * 1.0) and dividing by a float we already validated is greater than zero. All mutation of the tracked value uses set.
Let's build it
Place this device on your island and drag a slider_device into the TargetSlider slot. The slider's built-in widget is what appears on the player's canvas.
using { /Fortnite.com/Devices }
using { /Fortnite.com/UI }
using { /UnrealEngine.com/Temporary/UI }
using { /Verse.org/Simulation }
# Live-binds a slider widget to each player's UI and updates it in real time.
my_stat_sync_device := class<concrete>(creative_device):
# Wire a slider_regular widget here; its widget is shown on screen.
@editable TargetSlider : slider_regular = slider_regular{}
# The gameplay metric we visualize. Mutable so we can `set` it later.
@editable var CurrentCurrency : int = 0
# The slider's max value (its 100% mark). Must be > 0 to normalize.
@editable MaxCurrency : float = 100.0
OnBegin<override>()<suspends>: void =
Print("Launching stat sync...")
# Configure the slider's range once so SetValue maps cleanly.
TargetSlider.SetMinValue(0.0)
TargetSlider.SetMaxValue(1.0)
# Reach every player and attach the widget to their UI.
for (Player : GetPlayspace().GetPlayers()):
# GetPlayerUI is <decides>: bind it with [] in a failure context.
if (UI := GetPlayerUI[Player]):
# Put the slider widget onto this player's canvas.
UI.AddWidget(TargetSlider)
Print("Widget added to player canvas.")
# Coroutine loop: push the latest metric to the slider forever.
loop:
# VC_IntMod(No, and) no fallible int / : convert to float, then divide.
var NormVal : float = 0.0
if (MaxCurrency > 0.0):
set NormVal = (CurrentCurrency * 1.0) / MaxCurrency
# SetValue clamps into the slider's [0,1] range automatically.
TargetSlider.SetValue(NormVal)
# Yield to other coroutines between updates.
Sleep(0.25)
# Verse Cortex (UEFN-227): total integer modulo — Verse has no `%` operator.
# Wraps the native fallible Mod[] so it can be used in any context.
VC_IntMod(A:int, B:int):int =
if (R := Mod[A, B]):
R
else:
0
# Verse Cortex (UEFN-227): total integer division — Verse `/` on ints is
# fallible and yields a rational; this returns a plain int (floor), 0 when B<=0.
VC_IntDiv(A:int, B:int):int =
if (B > 0, R := Mod[A, B], Q := Floor[(A - R) * 1.0 / (B * 1.0)]):
Q
else:
0```
## Try it yourself
- **Drive the value from events**: Give the device an `@editable GainTrigger : trigger_device` and subscribe `GainTrigger.TriggeredEvent.Subscribe(OnGain)`; inside `OnGain` do `set CurrentCurrency = CurrentCurrency + 10`. The loop reflects it instantly.
- **Add a second slider**: Add another `slider_device` for `Rebirths`, attach it in the same `for` loop, and update it in the loop body.
- **Clamp inputs**: Before normalizing, guard against negatives with `if (CurrentCurrency < 0) { set CurrentCurrency = 0 }` so the slider never goes below empty.
## Recap
Widget state binding keeps your presentation synced with gameplay. You attached a `slider_device`'s `Widget` to each player via the fallible `GetPlayerUI[Player]` binding and `AddWidget`, then pushed live updates with a `loop` + `Sleep` coroutine. The two rules that keep this compiling: fallible `[]` calls belong inside an `if`/`for` condition, and you avoid `%` / fallible integer `/` by normalizing through floats.
Check your understanding
Test yourself with an interactive quiz and track your progress + earn XP — free for members.
Turn this into a guided course
Add Widget State Binding & Real-Time UI Updates in Verse to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.
References
Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.