Overview
branch is not a placed device — it's a core Verse expression for concurrency. When execution hits a branch block, Verse immediately kicks off that block as an independent background task and then, without waiting, continues to the very next line. The branched work runs on its own; your main flow never pauses for it.
The game problem it solves: async work that shouldn't block. Imagine a disappearing platform. A player steps on a trigger, the platform hides instantly, and then — after a random delay — it reappears. If you called Sleep() directly in your event handler, the whole handler would stall for the duration of the sleep. With branch, you launch the "wait then reappear" task in the background and immediately return, keeping the trigger responsive for the next player.
Reach for branch when:
- You want to start a delayed or looping task and keep going.
- You don't need the task's result (fire-and-forget).
- You'd otherwise be tempted to
spawna function just to avoid blocking.
Because branch calls async code, it must appear inside a <suspends> context (like OnBegin or a <suspends> method). The branched body can call things like Sleep() and device methods such as a prop's Show()/Hide() or a Patchwork tile's Trigger().
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Let's build a disappearing platform. A trigger device fires when a player steps on the platform prop. The platform hides instantly, and a background branch task waits a random amount of time, then shows it again — all without blocking the trigger for other players.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
using { /Verse.org/Random }
disappearing_platform_device := class(creative_device):
# The trigger the player steps on (a Patchwork trigger with TriggeredEvent).
@editable
StepTrigger : trigger_device = trigger_device{}
# The platform prop that disappears and reappears.
@editable
Platform : creative_prop = creative_prop{}
# Shortest reappear delay in seconds.
@editable
MinDelay : float = 2.0
# Longest reappear delay in seconds.
@editable
MaxDelay : float = 5.0
OnBegin<override>()<suspends>:void =
# Wire the trigger's event to our handler.
StepTrigger.TriggeredEvent.Subscribe(OnStepped)
# Handler runs when a player steps on the trigger.
OnStepped(Agent : agent):void =
# Hide the platform right away.
Platform.Hide()
# Fire-and-forget: launch the reappear task in the background.
# The handler returns immediately; the wait happens off to the side.
branch:
ReappearAfterDelay()
# Async task: wait a random time, then bring the platform back.
ReappearAfterDelay()<suspends>:void =
Delay := GetRandomFloat(MinDelay, MaxDelay)
Sleep(Delay)
Platform.Show()
Line by line:
- The
usinglines pull increative_device/trigger_device/creative_prop(Devices), the Patchwork trigger event,Sleep(Simulation) andGetRandomFloat(Random). @editablefields expose the trigger, the platform prop, and two delay tuning floats in UEFN's Details panel. You must declare devices as fields to call them — a bareTrigger.Method()fails with 'Unknown identifier'.OnBeginis our<suspends>entry point. We subscribe theTriggeredEventto theOnSteppedmethod. Subscription is done here, once.OnStepped(Agent : agent)is the event handler method at class scope. It callsPlatform.Hide()immediately.- The
branch:block launchesReappearAfterDelay()as a background task.OnSteppedthen finishes right away — it does not wait for the sleep. ReappearAfterDelayis<suspends>because it callsSleep. It picks a random delay withGetRandomFloat, waits, then callsPlatform.Show()to restore the platform.
Because the wait is branched off, ten players can all trip the trigger and each hide/reappear cycle runs independently without ever freezing the handler.
Common patterns
Pattern 1 — Branch a Patchwork tile Trigger after a delay
Here we use the Patchwork Trigger() method (which removes the associated tile) fired from a background task, so the main flow isn't held up by the delay.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
delayed_tile_device := class(creative_device):
@editable
Tile : trigger_device = trigger_device{}
@editable
ArmDelay : float = 3.0
OnBegin<override>()<suspends>:void =
# Kick off an arming task, then keep running other setup.
branch:
ArmAndFire()
ArmAndFire()<suspends>:void =
Sleep(ArmDelay)
# Trigger the Patchwork tile after the delay.
Tile.Trigger()
Pattern 2 — Branch a looping cosmetic while gameplay continues
branch shines for background loops. Here a prop pulses (hide/show) forever without ever blocking OnBegin.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
blinking_prop_device := class(creative_device):
@editable
Beacon : creative_prop = creative_prop{}
@editable
BlinkRate : float = 1.0
OnBegin<override>()<suspends>:void =
# Launch the endless blink loop in the background.
branch:
BlinkForever()
# This line runs immediately, the loop keeps blinking on its own.
Beacon.Show()
BlinkForever()<suspends>:void =
loop:
Beacon.Hide()
Sleep(BlinkRate)
Beacon.Show()
Sleep(BlinkRate)
Pattern 3 — Fire multiple independent branches from one event
Each branch is its own task, so you can start several at once and they all run in parallel.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
multi_branch_device := class(creative_device):
@editable
StartTrigger : trigger_device = trigger_device{}
@editable
PropA : creative_prop = creative_prop{}
@editable
PropB : creative_prop = creative_prop{}
OnBegin<override>()<suspends>:void =
StartTrigger.TriggeredEvent.Subscribe(OnStart)
OnStart(Agent : agent):void =
# Two independent background tasks with different timings.
branch:
HideThenShow(PropA, 2.0)
branch:
HideThenShow(PropB, 4.0)
HideThenShow(Prop : creative_prop, Wait : float)<suspends>:void =
Prop.Hide()
Sleep(Wait)
Prop.Show()
Gotchas
branchneeds a<suspends>context. You can only writebranchwhere async is allowed — insideOnBegin<override>()<suspends>or another<suspends>method. A plain non-suspends event handler likeOnStepped(Agent : agent):voidcan still contain abranchblock, but the code the branch calls must itself be<suspends>.- Fire-and-forget means no result.
branchdoes not return a value and you can'tawaitit. If you need the result of the async work, usespawn/race/syncstructured concurrency instead. - The branched task is tied to its scope. When the surrounding structured context ends, outstanding branched tasks may be cancelled. For endless work started in
OnBegin, that's typically fine becauseOnBegin's scope lives with the device. - Declare devices as
@editablefields. CallingPlatform.Hide()only works becausePlatformis a field on thecreative_deviceclass. A bare reference fails with 'Unknown identifier'. - No int↔float auto-conversion.
GetRandomFloatreturns afloat;Sleeptakes afloat. Keep your delay values as floats (2.0, not2). - Unwrap
?agentfrom listenable events. Alistenable(agent)hands the handler a plainagent, but alistenable(?agent)gives you?agent— unwrap it withif (A := Agent?):before use. The PatchworkTriggeredEventislistenable(agent), so no unwrap is needed there.