Verse Field Event Parameters: Wiring Sliders & Buttons to Verse
Tutorial beginner compiles

Verse Field Event Parameters: Wiring Sliders & Buttons to Verse

Updated beginner Ui Verse Language Code verified
Code by Howtwoboss, from Using VERSE FIELD EVENT PARAMETERS for Sliders/Buttons in Fortnite Creative/UEFN! (Full Tutorial). We transcribed and compile-checked the Verse shown in the video — fixing or completing it where the on-screen code was incomplete — and wrote our own step-by-step breakdown. Watch the original to support the creator.

This tutorial demonstrates how to build a dynamic UI system in UEFN using Verse Field Event Parameters. The creator walks through creating a Widget Blueprint with a slider and numbered buttons, configuring event parameters to pass data back into Verse, and writing the corresponding Verse script to manage per-player UI instances, handle asynchronous events using race and blocks, and clean up player data upon exit.

This is VerseIsland's own written breakdown of a community tutorial video — see the credit section below for the original creator and link.

1. UI Blueprint Setup & Interaction Properties (0:00–2:20)

In this part: How to create a Modal Dialog Variant widget blueprint and configure interaction properties for cross-platform compatibility.

  1. Create a new Widget Blueprint in the Content Drawer under User Interface, selecting 'Modal Dialog Variant'.
  2. Add a Grid Panel for layout, a Slider component, and multiple Button components.
  3. Add Text elements to each button displaying numbers (e.g., 1, 2, 3, 4, 5).
  4. Enable Focusable on the root widget and set Desired Focus Widget to the slider for controller support.
  5. Set Not Hittable to True (To Self Only) on non-interactive background panels to ensure mobile/virtual pointer interactions work correctly.

2. Defining Verse Fields & Event Parameters (2:20–4:00)

In this part: How to define custom Verse fields and events with parameters inside the Widget Blueprint's Variables panel.

  1. Open the 'Variables' window in the editor.
  2. Add a new Event named OnSliderChanged and set its parameter type to float to capture the slider's progress value.
  3. Add a regular Field named SliderPosition of type float to receive data from Verse.
  4. Add another Event named OnNumberClick with a parameter type of int to capture which button was pressed.
  5. Add a final Event named OnCloseClicked with zero parameters for handling UI dismissal.

3. Configuring Widget Bindings (4:00–6:50)

In this part: How to link UI widget states and events to the defined Verse fields and parameters using the Bindings panel.

  1. Select the Slider widget and bind its current value to the SliderPosition field.
  2. Bind the Exit button's On Clicked event to the On Close Clicked Verse event.
  3. For each numbered button, bind its On Clicked event to On Number Click and manually set Param 0 to the corresponding integer (1, 2, 3, 4, 5).
  4. Bind the Slider's On Slider Value Changed event to On Slider Changed. Add a condition where Value != -1 to trigger only on actual movement, and bind the slider's value to the event's parameter.

4. Verse Scripting: Device Structure & Maps (6:50–9:00)

In this part: Setting up the Verse device class, importing necessary modules, and declaring per-player data maps.

  1. Create a new Verse file named sliderUiDevice.verse.
  2. Import modules: /UnrealEngine.com/Temporary/UI, /Fortnite.com/UI, and /Verse.org/Assets.
  3. Define the class inheriting from creative_device.
  4. Declare two maps: MyUIPerPlayer : [player]?SliderUI = map() to store UI instances, and SliderValuePerPlayer : [player]float = map() to persist slider settings.
  5. Add an @editable Button : button_device field and subscribe Button.InteractedWithEvent to a CreatePlayerWidget function in OnBegin.

5. Verse Scripting: Player Widget Lifecycle (9:00–11:00)

In this part: How to instantiate UI widgets per player, attach them to the screen, and initialize their state.

  1. In CreatePlayerWidget(agent), extract the player using player(agent).
  2. Instantiate the UI: NewWidget := SliderUI().
  3. Retrieve the player's UI canvas: PlayerUI := GetPlayerUI[Player].
  4. Store the instance in the map: set MyUIPerPlayer[Player] = option(NewWidget).
  5. Attach the widget to the screen using PlayerUI.AddWidget(NewWidget, player_ui_slot(ui_input_mode.All)).
  6. Set focus to the new widget and initialize SliderValuePerPlayer[Player] to 0.0 if the player has no saved value.
  7. Spawn the asynchronous WaitForPlayer function to begin event listening.

6. Verse Scripting: Race Loops & Event Handling (11:00–14:20)

In this part: Implementing an asynchronous loop using race and blocks to await multiple UI events simultaneously.

  1. Define WaitForPlayer(player, SliderUI)<suspends>:void.
  2. Sleep briefly (0.1s) then restore any saved slider value to UIInstance.SliderPosition.
  3. Start a loop: with a logic flag Close initialized to false.
  4. Inside the loop, use race: containing multiple block: statements to await events concurrently:
    • Value := UIInstance.OnSliderChanged.Await()
    • Value := UIInstance.OnNumberClick.Await()
    • UIInstance.OnCloseClicked.Await()
  5. Unpack the event tuple payload using index notation (e.g., Value(0)) to access the passed parameter.
  6. Update the player maps and print values. If OnCloseClicked fires, call RemovePlayerWidget and set Close = true to break the loop.

7. Cleanup & In-Game Testing (14:20–17:44)

In this part: Properly removing UI widgets, cleaning up player maps to prevent memory leaks, and verifying functionality in-game.

  1. Implement RemovePlayerWidget(player) to safely detach the widget and clear the UI reference.
  2. Implement map cleanup by creating a new map that excludes the departing player's entry, then replacing the old map.
  3. Subscribe OnPlayerRemoved to GetPlaySpace().PlayerRemovedEvent to handle players leaving the session entirely.
  4. Test in-game: Press the interactive button to spawn the UI, move the slider to verify print logs update, click numbered buttons to verify integer passing, and exit to confirm the slider value persists on re-entry.

Code shown in the video

These are excerpts of the creator's OWN on-screen Verse code, captured from the video for reference — they are the creator's code, not VerseIsland's.

At 0:13 — compiled successfully

block:
Value := UIInstance.OnSliderChanged.Await()
if(set SliderValueForPlayer[Player] = Value(0))
Print("{Value(0)}")
block:
Value := UIInstance.OnNumberClick.Await()
Print("{Value(0)}")
block:
UIInstance.OnCloseClicked.Await()
RemovePlayerWidget(Player)
else
break
scoped
score_manager_device
scout_device
sentry_device

At 7:27 — compiled successfully

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Unrealengine.com/Temporary/Diagnostics }
using { /Unrealengine.com/Temporary/UI }
using { /Fortnite.com/UI }
using { /Verse.org/Assets }

sliderUIdevice := class(creative_device):

    var MyUIPerPlayer : [player]SliderUI = map[]

    OnBeginOverride() { suspends void =
    ()

At 7:47 — compiled successfully

sliderUiDevice.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/UI }
using { /Fortnite.com/UI }
using { /Verse.org/Assets }
sliderUiDevice = class(creative_device):
OnBegin(override)() { suspends } : void =
()

At 7:57 — compiled successfully

using {/UnrealEngine.com/Temporary/UI}
SliderUI<scoped {/howtwoboss@fortnite.com/VerseEventParametersTutorial}> := class<(/UnrealEngine.com/Temporary/UI)::widget>:

var SliderPosition:public::float = external ()
OnSliderChanged:public::event(tuple<float>) = external ()
OnNumberClick:public::event(tuple<int>) = external ()
OnCloseClicked:public::event(tuple()) = external ()

At 8:00 — compiled successfully

sliderUI.verse
# Copyright Epic Games, Inc. All Rights Reserved.
# Generated Digest of Verse API
# DO NOT modify this manually!
# Generated from build: +Fortnite/Release-41.10-CL-55335788
using {/UnrealEngine.com/Temporary/UI}
sliderUI<scoped {/howtwoboss@fortnite.com/VerseEventParametersTutorial> := class((/UnrealEngine.com/Temporary/UI/widget):
OnSliderChanged<public>:event<tuple<float>> = external {}
var SliderPosition<public>:float = external {}
OnNumberClick<public>:event<tuple<int>> = external {}
OnCloseClicked<public>:event<tuple<>> = external {}

At 8:06 — compiled successfully

Assets.digest.verse, # Copyright Epic Games, Inc. All Rights Reserved., SliderUI<scoped {...}> := class<...> : widget, var SliderPosition : public : float = external {}, OnNumberClick : public : event(tuple(int)) = external {}, OnCloseClicked : public : event(tuple()) = external {}

At 8:20 — compiled successfully

sliderUdevice = class(creative_device):
OnBegin(override)() <suspends>: void=
()
using { //Fortnite.com/Devices }
using { //Verse.org/Simulation }
using { //UnrealEngine.com/Temporary/Diagnostics }
using { //UnrealEngine.com/Temporary/UI }
using { //Fortnite.com/UI }
using { //Verse.org/Assets }

At 8:28 — compiled successfully

using { Fortnite.Devices }
using { Verse.org.Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /UnrealEngine.com/Temporary/UI }
using { Fortnite.UI }
using { Verse.org.Assets }

sliderUdevice := class(creative_device):

    var MyUIPerPlayer = {player}SliderUI = map()

    OnBeginOverlap() { suspends } void =
    ()

At 8:33 — compiled successfully

sliderValueVerse.verse, using creative;, using creativeDevice;, sliderDevice : class(creative_device), var MyPlayer : Player, [Player] Slider : ui_map, var SliderValue : Player, [Player] Input : ui_map, Button : button_device, OnBegin(override()) -> suspend: void, Button.InteractedWithEvent.Subscribe(CreatePlayerWidget);

At 8:58 — compiled successfully

sliderUidevice := class(creative_device):

At 9:30 — compiled successfully

@editable
Button : button_device = button_device{}

OnBegin(override)() <suspends> void=
    Button.InteractedWithEvent.Subscribe(CreatePlayerWidget)

CreatePlayerWidget(agent : agent) : void=
    if(player := player(agent));
        NewWidget := SliderUI{}
        if(PlayerUI := GetPlayerUI[Player], set MyUIPerPlayer[Player] = option(NewWidget));
        PlayerUI.
    AddWidget(Widget:widget)
    AddWidget(Widget:widget, Slot:player_ui_s1...
    Agent
    CreatePlayerWidget(agent:agent)

At 9:43 — compiled successfully

@editable
Button : button_device = button_device()
OnBegin(override){...}
Button.InteractionEvent.Subscribe(CreatePlayerWidget)
CreatePlayerWidget(agent : Agent) : void=
if(player := player(agent))
NewWidget := SliderUI()
if(@PlayerUI := GetPlayerUI)

At 10:24 — compiled successfully

Button.InteractedWithEvent.Subscribe(CreatePlayerWidget)
CreatePlayerWidget(Agent : agent) : void:
if(Player : SliderUI[
NewWidget := SliderUI[
if(PlayerUI := GetPlayerUI[Player], set MyUIPerPlayer[Player] = option(NewWidget)):
PlayerUI.AddWidget(NewWidget, player_ui_slot(ui_input_mode.All))
PlayerUI.SetFocus(NewWidget)
if(not SliderValuePerPlayer[Player] :=
if(set SliderValuePerPlayer[Player] = 0.0):
spawn[ WaitforPlayer(Player, NewWidget)]

At 11:00 — compiled successfully

if(not SliderValuePerPlayer[Player]); if(set SliderValuePerPlayer[Player] = 0.0); spawn( WaitforPlayer; WaitforPlayer(Player : player, UIInstance : SliderUI<:suspend:>:void=; Sleep(0.1); if(SavedValue := SliderValuePerPlayer[Player]); set UIInstance; UIInstance; WaitforPlayer(Player:player, UIInstance:SL; class_selector_ui_device (:classSelectedV...; SliderUI {OnSliderChanged:event(tuple{float,...

At 11:30 — compiled successfully

if(not SliderValuePerPlayer[Player]): if(set SliderValuePerPlayer[Player] = 0.0): spawn( WaitForPlayer(Player, NewWidget )) WaitForPlayer(Player : player, UIInstance : SliderUI)::<suspends>::void Sleep(0.1) if(SaveValue := SliderValuePerPlayer[Player]): set UIInstance.SliderPosition = SavedValue SavedValue slider_regular {DefaultValue:float} slider_ufo_device {MyUIPerPlayer...} vfx_spawner_device {effectEnabledEvent...} storm_controller_device {PhaseEndedEvent...} capture_item_spawner_device {ItemCaptured...} stat_creator_device {ValueChangedEvent...} sentry_device {AlertedEvent...} spire_spike_device {KnockbackEvent...}

At 12:00 — compiled successfully

PlayerUI.SetFocus(NewWidget)
if(not SliderValuePerPlayer[Player] = 0.0):
spawn( WaitPlayer(Player, UIInstance) )
WaitPlayer(Player : player, UIInstance: SliderUI)<suspends>:void
Sleep(0.1)
if(SavedValue := SliderValuePerPlayer[Player]):
set UIInstance.SliderPosition = SavedValue
var Close : logic = false
loop:
if(Close := false):
race:
block:
Value := UIInstance.OnSliderChanged.Await()
Await()
Concurrency_awaitable_Variance()
block:
else:
break

At 12:24 — compiled successfully

PlayerUI.SetFocus(NextWidget)
if(not SliderValueForPlayer[Player] = 0.0)
WaitForPlayer(Player = player, UIInstance = SliderUI):suspend:
SavedValue := SliderValueForPlayer[Player]
set UIInstance.SliderPosition = SavedValue
var Close : logic = false
loop:
race:
Value := Ui
material_block [DefaultTint:color = Default...
text_button_base [DefaultText:message = ...
vehicle_and_box_settings [PaintColor:?col
player_ui_slot [ZOrder:type:Xint where Q=...
disguise_device [ApplyDisguiseEvent:listen...
player_counter_device [CountSucceedEvent:.
texture_block [DefaultTint:color = defaul
switch_device [TurnedOnEvent:listenable:ag

At 13:00 — compiled successfully

WaitForPlayer(Player := player, UIInstance := SliderUI){suspends}:void= ... if( SliderValuePerPlayer[Player] = Value(0)):

At 13:22 — compiled successfully

set UIInstance.SliderPosition = SavedValue
var Close = logic = false
loop:
if close = false:
block:
Value := UIInstance_OnSliderChanged.Await()
if set SliderValuePerPlayer[Player] = Value()
Print( 'Value()')
block:
Value := UIInstance_
Button
Close
CreatePlayerWidget(Agent: agent)
GetGlobalTransform()
GetParentWidget()
GetRootWidget()
GetTransform()
GetVisibility()
Hide()
if

At 13:30 — compiled successfully

set UIInstance.SliderPosition = SavedValue
var Close : logic = false
loop(if (Close = false):
    race:
        block:
            Value := UIInstance.OnSliderChanged.Await()
            if(set SliderValuePerPlayer[Player] = Value(0))
                Print("{Value(0)}")
        block:
            Value := UIInstance.OnNumberClick.Await()
            Print("{Value(0)}")
        block:
            UIInstance.OnCloseClicked.Await()
            RemovePlayerWidgets(Player)
            set Close = true
    else:
        break

At 13:56 — compiled successfully

UIInstance.OnSliderChanged.Await(), Value := SliderValueForPlayer[Player] = Value(0), Print("Value:0"), UIInstance.OnNumberClick.Await(), Print("Value:0"), UIInstance.OnCloseClicked.Await(), RemovePlayerWidget(@Player), else:, break:, player, player_checkpoint_device, player_counter_device, player_hud_identifier_all, player_marker_device

At 14:29 — compiled successfully

student_widgets.verse
Value :: UIInstance.OnNumberClick.Async()
Print("Value("0")")
UIInstance.OnCloseClicked.Async()
RemovePlayerWidget(Player
ui Close = True
RemovePlayerWidget(Player : player): void:
if(widgetOpt)

At 14:47 — compiled successfully

slider.verse WaitForPlayer(Player player, UIInstance : SlideUI)(suspends): void Print(ValueOf(0)) blink UIInstance.OnCloseClicked.Await() RemovePlayerWidget(Player) set Close = True else break RemovePlayerWidget(Player : player): void if(WidgetOpt := MyWaitForPlayer(Player), Widget := WidgetOpt): if(PlayerUI := GetPlayerUI(Player)):

At 15:00 — compiled successfully

slider_device : class(creative_device)
var MyPerfPlayer : [player]SliderUI = map{}
var SliderValuePerPlayer : [player]float = map{}
Button : button_device = button_device{}
OnBeginOverride()
CreatePlayerWidget(Agent agent)
MyWidget : SliderUI{}

At 15:30 — compiled successfully

Value := UIInstance.OnSliderChanged.Await();
If(set.SliderValueForPlayer[Player] = Value): Print("{Value}");
Value := UIInstance.OnNumberClick.Await();
UIInstance.OnCloseClicked.Await();
RemovePlayerWidget(Player); set.Close = true;

RemovePlayerWidget(Player : player).void:
If(WidgetOpt = MyPlayerUI[Player]): Widget = WidgetOpt;
If(PlayerUI = GetPlayerUI(Player)):
    PlayerUI.RemoveWidget(Widget);
var NewMap := [Player]:Fill(0) = Map();
for(Key -> MyPlayerUI:Key, Key <> Player):
    If(set.NewMap[Key] = Value):
        set.MyPlayerUI = NewMap;

MyPlayerLayer
sliderUIDevice [MyPlayerUI:"player"]51;

At 16:00 — compiled successfully

sliderDevice = class(creative_device)

    var MyNilPlayer : [player]SlideUi = map()
    var SliderValuePerPlayer : [player]Float = map()
    mutable
    Button = button_device = button_device()

OnBeginOverride(yesSuspend: void):

    Button.InteractedWithEvent.Subscribe(CreatePlayerWidget)
    GetPlaySpace().PlayerRemovedEvent.Subscribe(OnPlayerRemoved)

CreatePlayerWidget(agent : agent): void
    if (player := agent.player) {
        NewWidget := SliderUi{}
        if (PlayerUi := GetPlayerUi(player), set MyNilPlayer[player] = option(NewWidget)) {
            PlayerUi.AddWidget(NewWidget, PlayerUi slot {slotMode = ui_input_mode_All})
            PlayerUi.SetFocus(NewWidget)
        }
        if (not SliderValuePerPlayer[player]) {
            SliderValuePerPlayer[player] = 0.0;

At 16:07 — compiled successfully

Things mentioned in the video

Names and features the video mentions, as spoken or shown on screen (not yet independently verified against the current API):

Mentioned Timestamp Context
OnSliderChanged 3:29 Event name defined in Widget Blueprint Variables panel with a float parameter. Shown in frame. (Future/Speculative: Creator explicitly notes they hope to support multiple parameters in future engine updates.)
OnNumberClick 5:44 Event name defined in Widget Blueprint Variables panel with an int parameter. Spoken by creator.
OnCloseClicked 6:30 Event name defined in Widget Blueprint Variables panel with zero parameters. Spoken by creator.
SliderPosition 5:29 Regular Verse Field of type float used to pass data from Verse to the UI slider. Spoken by creator.
player_ui_slot 10:11 Function used in AddWidget call to specify input mode. Shown in code frame.
ui_input_mode.All 10:11 Enum value passed to player_ui_slot to enable full input handling. Shown in code frame.
GetPlayerUI 10:00 Function called to retrieve the player's UI canvas. Transcript says 'GetPlayerUI[Player]', frame shows autocomplete.
Option<T> 8:48 Syntax ?SliderUI used for optional map values. Shown in code frame.
race 12:00 Verse concurrency construct used to await multiple events simultaneously. Shown in code frame.
block 12:00 Construct nested inside race to define individual event waiting logic. Shown in code frame.
tuple<float> 7:57 Type signature for the OnSliderChanged event parameter. Shown in generated digest/code frame.
tuple<int> 7:57 Type signature for the OnNumberClick event parameter. Shown in generated digest/code frame.
Value(0) 13:00 Index notation used to unpack the first element of the event tuple payload. Shown in code frame. Note: This specific indexing syntax reflects the UEFN build/version demonstrated in the video.
InteractedWithEvent 9:43 Event on button_device subscribed to trigger UI creation. Shown in code frame.
PlayerRemovedEvent 16:00 Event on PlaySpace subscribed to handle player leave cleanup. Shown in code frame.
Modal Dialog Variant 0:34 Widget Blueprint parent class selected during creation. Shown in dropdown menu.
Focusable 2:30 UI property enabled on root widget for controller/gamepad navigation. Spoken by creator.
Desired Focus Widget 2:30 UI property set to the slider element to direct initial controller focus. Spoken by creator.
Not Hittable 2:00 UI property set to True (To Self Only) on background panels to allow touch/mouse passthrough. Spoken by creator.
Variables 2:53 Editor panel/window opened to define custom Verse fields and events for the widget. Shown in frame.
View Bindings 4:08 Editor panel used to visually wire widget states and events to the defined Verse fields. Shown in frame.
creative_device 7:47 Base class inherited by the custom Verse device script. Shown in code frame.
MyUIPerPlayer 8:48 Map variable declared to store per-player UI widget instances. Shown in code frame.
SliderValuePerPlayer 8:48 Map variable declared to persist and retrieve slider float values per player. Shown in code frame.
button_device 9:43 Editable field type assigned to the world-placed trigger button. Shown in code frame.
CreatePlayerWidget 9:43 Custom function subscribed to the button's interaction event to spawn UI. Shown in code frame.
AddWidget 10:00 Method called on the PlayerUI object to attach the instantiated widget to the screen. Shown in code frame.
SetFocus 10:24 Method called to direct input focus to the newly spawned widget. Shown in code frame.
WaitForPlayer 11:00 Asynchronous function defined to handle the main event-listening loop. Shown in code frame.
Sleep 11:30 Called inside WaitForPlayer to pause execution briefly before restoring saved state. Shown in code frame.
RemovePlayerWidget 14:47 Function implemented to detach widgets from the player screen and clean up references. Shown in code frame.
GetPlaySpace 16:00 Function called to access global PlaySpace events for session-level cleanup. Shown in code frame.
OnBegin 7:47 Override method where device initialization and event subscriptions occur. Shown in code frame.
loop 12:00 Verse construct used to repeatedly execute the race/event-waiting block until closed. Shown in code frame.
logic 12:00 Variable type used for the Close flag that controls the loop termination condition. Shown in code frame.
.Await() 12:30 Method called on Verse events to suspend the task until the event fires. Shown in code frame.
tuple() 7:57 Type signature indicating zero parameters for the OnCloseClicked event. Shown in generated digest/code frame.
external 7:57 Keyword used to declare Verse fields and events that are sourced from the compiled Blueprint asset. Shown in code frame.
option() 10:00 Wrapper function used to safely store potentially null UI instances in the player map. Shown in code frame.
map() 8:48 Constructor used to initialize empty key-value dictionaries for per-player data storage. Shown in code frame.
Print() 13:00 Function called to output captured parameter values to the debug console. Shown in code frame.
OnBeginOverride 7:30 Alternative syntax/name observed in early code drafts for the device initialization method. Shown in code frame.

Want to go further?

  • Mastering Verse Field Event Parameters: A step-by-step guide to passing dynamic data from UMG widgets to Verse.
  • The Race/Block Pattern: How to handle multiple UI inputs asynchronously in UEFN without blocking the game thread.
  • Per-Player UI Management: Best practices for instantiating, attaching, and cleaning up HUD widgets in Verse.
  • Widget Bindings Deep Dive: Connecting slider values and button clicks to Verse events using the UEFN Bindings panel.

Credit

This breakdown is based on a video by Howtwobosswatch the original for the full walkthrough.

Get the complete code — free

You've read the full walkthrough. The complete, copy-paste-ready Verse solution is free for members — sign in to unlock it.

Free with your BrainDead.TV / BrainDeadGuild Discord account. The walkthrough above is always free.

Turn this into a guided course

Add This tutorial demonstrates how to build a dynamic UI system in UEFN using Verse Field Event Parameters. The creator walks through creating a Widget Blueprint wi 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.

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.

Comments

    Sign in to vote, comment, or suggest an edit. Sign in