Overview
On a sunny cove finish line, you rarely care about the whole crowd — you care about the first person who qualifies. Maybe it's the first player standing on the dock, the first agent whose score cleared a threshold, or the first teleporter that's still enabled. That's exactly what Verse's first expression does: it iterates a collection, tests each element with a <decides> condition, and returns the very first element that succeeds — then stops looking.
first is not a device — it's a core Verse control-flow expression (a cousin of for). Because it can fail (there might be no match), you call it inside a failable context like if (Winner := first(...)):. In this article we pair it with real devices — a damage_volume_device used as a trigger zone to gather agents, a cinematic_sequence_device to play the win cutscene, and a teleporter_device to send the winner home — so the abstract idea lands as a concrete game moment.
Reach for first whenever the answer is "the earliest element that qualifies": first ready player, first free spawner, first enabled teleporter. Use for when you need all matches instead.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
The scene: a wooden dock on a bright cel-shaded shore. A large damage_volume_device (with damage set to 0 so it acts as a harmless detection zone) covers the end of the dock. When any player runs into it, we scan the agents currently in the zone and grab the first one — that's our winner. We play the victory cinematic for them and teleport them to a champion's platform.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
dock_finish_line := class(creative_device):
# The detection zone at the end of the dock. Set its damage to 0 in the editor.
@editable
FinishZone : damage_volume_device = damage_volume_device{}
# The victory cutscene that plays for the winner.
@editable
WinCinematic : cinematic_sequence_device = cinematic_sequence_device{}
# Teleporter that whisks the winner to the champion platform.
WinnerTeleporter : teleporter_device = teleporter_device{}
# Have we already crowned a winner this round?
var WinnerCrowned : logic = false
OnBegin<override>()<suspends>:void =
# Make sure the zone deals no damage — it's just a trip-wire.
FinishZone.SetDamage(0)
# Listen for anyone entering the finish zone.
FinishZone.AgentEntersEvent.Subscribe(OnAgentEntered)
OnAgentEntered(Agent : agent) : void =
# Only crown one winner per round.
if (not WinnerCrowned?):
CrownFirstArrival()
CrownFirstArrival() : void =
# Everyone currently standing in the zone.
AgentsHere := FinishZone.GetAgentsInVolume()
# We simply grab the first agent in the volume.
if (Winner := AgentsHere[0]):
set WinnerCrowned = true
# Reward the winner with the cutscene and a teleport.
WinCinematic.Play(Winner)
WinnerTeleporter.Teleport(Winner)```
**Line by line:**
- The three `@editable` fields let you drop the device into the level and wire the real placed `damage_volume_device`, `cinematic_sequence_device`, and `teleporter_device` in the Details panel.
- `var WinnerCrowned : logic = false` is our guard so a whole stampede doesn't re-trigger the cutscene.
- In `OnBegin`, `FinishZone.SetDamage(0)` turns the damage volume into a harmless trip-wire, then we `Subscribe` our handler to `AgentEntersEvent`.
- `OnAgentEntered` receives the entering `agent` directly (this event's payload is a plain `agent`, not `?agent`). We only proceed if no winner has been crowned yet.
- `GetAgentsInVolume()` returns `[]agent`. The `first (A : AgentsHere): A` expression iterates that array; the body `A` always succeeds, so `first` returns the *earliest* agent in the list. The `if (Winner := ...)` unwraps it — if the array were empty, `first` fails and the block is skipped.
- With a `Winner`, we flip the guard, call `WinCinematic.Play(Winner)` (the agent overload, required because the cinematic is set to a specific instigator), and `WinnerTeleporter.Teleport(Winner)`.
## Common patterns
**1. First player over a score threshold.** Pair `first` with a real device by using the winner's agent to grant points and stop a `timer_device`. Here we scan the zone's occupants for the first agent, then reward them.
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
first_to_finish := class(creative_device):
@editable
Zone : damage_volume_device = damage_volume_device{}
@editable
RaceTimer : timer_device = timer_device{}
@editable
ScoreAward : score_manager_device = score_manager_device{}
OnBegin<override>()<suspends>:void =
Zone.SetDamage(0)
Zone.AgentEntersEvent.Subscribe(OnEntered)
OnEntered(Agent : agent) : void =
Occupants := Zone.GetAgentsInVolume()
# Grab the first agent standing on the finish pad.
if (Champ := first(A : Occupants): A):
# Stop the race clock and hand the champ their points.
RaceTimer.Reset(Champ)
ScoreAward.Activate(Champ)
2. First enabled teleporter fallback. When you keep a list of teleporters, first lets you pick one to send a spawned player to. This snippet grabs the first teleporter in an array and links it back.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
spawn_router := class(creative_device):
@editable
Spawner : player_spawner_device = player_spawner_device{}
# Wire several teleporters here in the editor.
@editable
Exits : []teleporter_device = array{}
OnBegin<override>()<suspends>:void =
Spawner.SpawnedEvent.Subscribe(OnSpawned)
OnSpawned(Agent : agent) : void =
# Route the freshly spawned agent through the first available exit.
if (Exit := first(T : Exits): T):
Exit.ActivateLinkToTarget()
Exit.Teleport(Agent)
3. First player reference match. first combined with a player_reference_device's IsReferenced check finds the earliest agent in a zone that the device is tracking, then activates the cinematic for them.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
tracked_arrival := class(creative_device):
@editable
Zone : damage_volume_device = damage_volume_device{}
@editable
TrackedRef : player_reference_device = player_reference_device{}
@editable
Cutscene : cinematic_sequence_device = cinematic_sequence_device{}
OnBegin<override>()<suspends>:void =
Zone.SetDamage(0)
Zone.AgentEntersEvent.Subscribe(OnEntered)
OnEntered(Agent : agent) : void =
Occupants := Zone.GetAgentsInVolume()
# first + a <decides> body: keep only the tracked agent.
if (VIP := first(A : Occupants): TrackedRef.IsReferenced[A]; A):
Cutscene.Play(VIP)
Gotchas
firstcan fail. If the collection is empty or nothing matches, the whole expression fails — so it must live in a failable context (if (X := first(...)):,for, or a<decides>function). Don't try to bind its result unconditionally.- The body decides the match. In
first(A : Xs): SomeCheck[A]; A, the semicolon-separated body runs as a failable block. IfSomeCheck[A]fails, that element is skipped andfirstmoves on. The final expression (A) is what gets returned. firstreturns the element, not an index. Unlike a manual loop counter, you get the value directly. If you need position, iterate withforand track it yourself.- Event payload types differ.
damage_volume_device.AgentEntersEventhands you a plainagent— no?to unwrap. Buttimer_device.SuccessEventislistenable(?agent); that one needsif (A := MaybeAgent?):before use. Match your handler signature to the real event type. - Instigator overloads.
cinematic_sequence_device.Play(Agent)andteleporter_device.Teleport(Agent)are the agent overloads — use them when the device is set to anything other than Everyone. Calling the no-argPlay()on an instigator-scoped device silently does nothing. - Damage volume as a trigger. A
damage_volume_devicewithSetDamage(0)is a handy detection zone, but remember its default damage may be nonzero in the editor — callSetDamage(0)inOnBeginif you only want detection.