Overview
In Verse, loop is an expression that repeats its body indefinitely. Unlike for or while in other languages, loop has no built-in condition — it runs until you explicitly call break inside the body, or until the surrounding async context is cancelled (e.g. by race). Because loop blocks the current coroutine, you almost always pair it with Sleep() so it yields between iterations and doesn't starve other tasks.
When to reach for loop + break:
- A platform that alternates between visible and invisible on a timer
- A countdown that ticks every second and stops at zero
- A VFX cycle that restarts until a player triggers an event
- Any "keep doing X until Y happens" pattern
Without break, the loop runs for the entire game session. With break, you get a clean, readable exit at exactly the right moment.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario: A glowing platform blinks on and off every few seconds. When a player finally lands on a pressure plate nearby, the platform stops blinking and stays visible — the vault door is now permanently open.
This example uses:
loopto keep the blink cycle runningbreakto stop the cycle when the plate firesSleep()to control the on/off timingcreative_prop.Hide()/.Show()to toggle the platform meshvfx_spawner_device.Enable()/.Disable()to sync a glow effect
using { /Verse.org/Simulation }
using { /Fortnite.com/Devices }
using { /Fortnite.com }
# Place this device in your UEFN scene, then assign the three
# editable references in the Details panel.
blinking_vault_device := class(creative_device):
# The platform prop that blinks on and off.
@editable
Platform : creative_prop = creative_prop{}
# A VFX Spawner placed on the platform for the glow effect.
@editable
GlowVFX : vfx_spawner_device = vfx_spawner_device{}
# A Trigger Device — player steps on it to stop the blinking.
@editable
Plate : trigger_device = trigger_device{}
# How long (seconds) the platform stays visible each cycle.
@editable
OnDuration : float = 2.0
# How long (seconds) the platform stays hidden each cycle.
@editable
OffDuration : float = 1.5
# Tracks whether the plate has been triggered.
var PlateTriggered : logic = false
# Called when the plate fires — sets the flag that breaks the loop.
OnPlateTriggered(Agent : ?agent) : void =
set PlateTriggered = true
OnBegin<override>()<suspends> : void =
# Subscribe so any trigger from the plate sets our flag.
Plate.TriggeredEvent.Subscribe(OnPlateTriggered)
# Start the blink loop.
loop:
# --- VISIBLE phase ---
Platform.Show()
GlowVFX.Enable()
Sleep(OnDuration)
# Check the exit condition AFTER the sleep so the
# platform is always fully visible when the player lands.
if (PlateTriggered?):
break # Leave the loop; platform stays visible.
# --- HIDDEN phase ---
Platform.Hide()
GlowVFX.Disable()
Sleep(OffDuration)
# Check again after the hidden phase too.
if (PlateTriggered?):
# Make sure we restore visibility before exiting.
Platform.Show()
GlowVFX.Enable()
break
Line-by-line explanation:
| Lines | What's happening |
|---|---|
@editable fields |
Wired in the UEFN Details panel — no hard-coding |
var PlateTriggered |
Shared mutable flag between the event handler and the loop |
OnPlateTriggered |
Event handler (class-scope method) — sets the flag when the plate fires |
Plate.TriggeredEvent.Subscribe(...) |
Registers the handler; TriggeredEvent sends ?agent |
loop: |
Starts the infinite blink cycle |
Platform.Show() / Hide() |
Toggles prop visibility and collision |
GlowVFX.Enable() / Disable() |
Keeps the VFX in sync with the prop |
Sleep(OnDuration) |
Yields for N seconds — other coroutines run during this time |
if (PlateTriggered?): break |
Exits the loop cleanly; code after loop: resumes |
Common patterns
Pattern 1 — Countdown timer that stops at zero
A classic round timer: counts down from a starting value, prints nothing (uses Sleep as the tick), and breaks when it hits zero. Pair this with a HUD message device in your real project.
using { /Verse.org/Simulation }
using { /Fortnite.com/Devices }
countdown_device := class(creative_device):
# Total seconds to count down.
@editable
StartSeconds : int = 30
OnBegin<override>()<suspends> : void =
var Remaining : int = StartSeconds
loop:
if (Remaining <= 0):
# Time is up — exit the loop.
break
# Wait one second, then decrement.
Sleep(1.0)
set Remaining = Remaining - 1
# Code here runs only after break — trigger end-of-round logic.
# e.g. EndRoundDevice.Activate()
Key point: The break check comes before the Sleep so the loop exits immediately when the counter reaches zero rather than sleeping one extra second.
Pattern 2 — Random-interval VFX burst cycle
A VFX spawner fires a burst at a random interval between 1 and 4 seconds, forever. No break needed here — the loop runs for the whole game. This demonstrates loop without break as a valid "run forever" pattern, combined with GetRandomFloat.
using { /Verse.org/Simulation }
using { /Fortnite.com/Devices }
using { /Fortnite.com }
using { /Verse.org/Random }
random_burst_device := class(creative_device):
# A VFX Spawner set to Burst mode in its device settings.
@editable
BurstVFX : vfx_spawner_device = vfx_spawner_device{}
# Minimum seconds between bursts.
@editable
MinDelay : float = 1.0
# Maximum seconds between bursts.
@editable
MaxDelay : float = 4.0
OnBegin<override>()<suspends> : void =
loop:
# Fire the burst VFX.
BurstVFX.Restart()
# Wait a random amount of time before the next burst.
var Delay : float = GetRandomFloat(MinDelay, MaxDelay)
Sleep(Delay)
# No break — this runs for the entire game session.
Pattern 3 — race as an alternative exit strategy
Sometimes you want the loop to stop when an external async event completes, not a flag. Use race to run the blink loop against a one-shot awaiter. Whichever branch finishes first cancels the other.
using { /Verse.org/Simulation }
using { /Fortnite.com/Devices }
using { /Fortnite.com }
race_exit_device := class(creative_device):
@editable
Platform : creative_prop = creative_prop{}
@editable
GlowVFX : vfx_spawner_device = vfx_spawner_device{}
# When this event fires, the blink loop is cancelled via race.
@editable
StopButton : button_device = button_device{}
# Runs forever, blinking the platform.
BlinkForever()<suspends> : void =
loop:
Platform.Hide()
GlowVFX.Disable()
Sleep(1.0)
Platform.Show()
GlowVFX.Enable()
Sleep(2.0)
# Waits for the button press and then returns, ending the race.
WaitForStop()<suspends> : void =
StopButton.InteractedWithEvent.Await()
OnBegin<override>()<suspends> : void =
# race cancels BlinkForever the moment WaitForStop returns.
race:
BlinkForever()
WaitForStop()
# After the race, ensure the platform is visible.
Platform.Show()
GlowVFX.Enable()
Gotchas
1. Always Sleep inside a loop or you'll hang the frame
A loop with no Sleep and no break will spin forever in the same tick, freezing your island. Every loop body must either call Sleep() (even Sleep(0.0) to yield once) or be guaranteed to break quickly.
2. break only exits the innermost loop
If you nest two loop expressions, break exits only the inner one. To exit both, use a shared flag and check it in the outer loop too, or restructure with race.
3. TriggeredEvent sends ?agent — always unwrap before use
trigger_device.TriggeredEvent is listenable(?agent). Your handler signature must be (Agent : ?agent) : void. If you need the actual agent, unwrap it: if (A := Agent?) { ... }. Passing the raw ?agent to APIs that expect agent is a compile error.
4. logic flags vs. Await() — know the trade-off
Using a var logic flag (Pattern 1 style) is simple but introduces a one-iteration lag: the loop checks the flag only at the top of each cycle. For instant exits, prefer race with Await() (Pattern 3) so the loop is cancelled the moment the event fires.
5. Sleep takes a float, not an int
Verse does not auto-convert int to float. Sleep(2) is a compile error. Always write Sleep(2.0). If your delay is stored as int, convert explicitly: Sleep(float(MyIntDelay)).
6. vfx_spawner_device lives in /Fortnite.com not /Fortnite.com/Devices
The vfx_spawner_device type is declared inside the Devices module under /Fortnite.com, so you need using { /Fortnite.com } (not just /Fortnite.com/Devices) for it to resolve. Missing this import gives an "Unknown identifier" error.