Overview
The timer_device tracks elapsed or remaining time and signals three key events your Verse code can subscribe to:
SuccessEvent— fires when the timer is explicitly completed (the player won the race).FailureEvent— fires when the countdown hits zero without being completed (time ran out).StartUrgencyModeEvent— fires when the timer enters its configurable "urgency" window (e.g., last 10 seconds), letting you add a visual or audio cue.
Beyond events, the device exposes a full control surface: Start, Pause, Resume, ResetForAll, Complete, SetActiveDuration, and more — all callable from Verse. You can drive the timer per-agent or globally, making it equally useful for solo challenges and multiplayer races.
Reach for timer_device when:
- A game loop needs a hard time limit (escape the cove before the tide comes in).
- You want a visible HUD countdown without building custom UI.
- You need urgency-mode hooks to ramp up music or visual effects in the final stretch.
- You need per-player timers in a competitive minigame.
API Reference
timer_device
Provides a way to keep track of the time something has taken, either for scoreboard purposes, or to trigger actions. It can be configured in several ways, either acting as a countdown to an event that is triggered at the end, or as a stopwatch for an action that needs to be completed before a set time runs out.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
timer_device<public> := class<concrete><final>(creative_device_base):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
SuccessEvent |
SuccessEvent<public>:listenable(?agent) |
Signaled when the timer completes or ends with success. Sends the agent that activated the timer, if any. |
FailureEvent |
FailureEvent<public>:listenable(?agent) |
Signaled when the timer completes or ends with failure. Sends the agent that activated the timer, if any. |
StartUrgencyModeEvent |
StartUrgencyModeEvent<public>:listenable(?agent) |
Signaled when the timer enters Urgency Mode. Sends the agent that activated the timer, if any. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>(Agent:agent):void |
Enables this device for Agent. |
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>(Agent:agent):void |
Disables this device for Agent. While disabled this device will not receive signals. |
Disable |
Disable<public>():void |
Disables this device. While disabled this device will not receive signals. |
ResetForAll |
ResetForAll<public>(Agent:agent):void |
Resets the timer back to its base time and stops it for all agents. |
ResetForAll |
ResetForAll<public>():void |
Resets the timer back to its base time and stops it for all agents. |
Start |
Start<public>(Agent:agent):void |
Starts the timer for Agent. |
Start |
Start<public>():void |
Starts the timer. |
Pause |
Pause<public>(Agent:agent):void |
Pauses the timer for Agent. |
Pause |
Pause<public>():void |
Pauses the timer. |
Resume |
Resume<public>(Agent:agent):void |
Resumes the timer for Agent. |
Resume |
Resume<public>():void |
Resumes the timer. |
Complete |
Complete<public>(Agent:agent):void |
Completes the timer for Agent. |
Complete |
Complete<public>():void |
Completes the timer. |
StartForAll |
StartForAll<public>(Agent:agent):void |
Starts the timer for all agents. |
StartForAll |
StartForAll<public>():void |
Starts the timer for all agents. |
PauseForAll |
PauseForAll<public>(Agent:agent):void |
Pauses the timer for all agents. |
PauseForAll |
PauseForAll<public>():void |
Pauses the timer for all agents. |
ResumeForAll |
ResumeForAll<public>(Agent:agent):void |
Resumes the timer for all agents. |
ResumeForAll |
ResumeForAll<public>():void |
Resumes the timer for all agents. |
CompleteForAll |
CompleteForAll<public>(Agent:agent):void |
Completes the timer for all agents. |
CompleteForAll |
CompleteForAll<public>():void |
Completes the timer for all agents. |
Save |
Save<public>(Agent:agent):void |
Saves this device's data for Agent. |
Load |
Load<public>(Agent:agent):void |
Loads this device's saved data for Agent. |
ClearPersistenceData |
ClearPersistenceData<public>(Agent:agent):void |
Clears this device's saved data for Agent. |
ClearPersistenceDataForAll |
ClearPersistenceDataForAll<public>(Agent:agent):void |
Clears this device's saved data for all agents. |
ClearPersistenceDataForAll |
ClearPersistenceDataForAll<public>():void |
Clears this device's saved data for all agents. |
SetActiveDuration |
SetActiveDuration<public>(Time:float, Agent:agent):void |
Sets the remaining time (in seconds) on the timer, if active, on Agent. |
SetActiveDuration |
SetActiveDuration<public>(Time:float):void |
Sets the remaining time (in seconds) on the timer, if active. Use this function if the timer is set to use the same time for all agent's. |
GetActiveDuration |
GetActiveDuration<public>(Agent:agent)<transacts>:float |
Returns the remaining time (in seconds) on the timer for Agent. |
GetActiveDuration |
GetActiveDuration<public>()<transacts>:float |
Returns the remaining time (in seconds) on the timer if it is set to be global. |
SetLapTime |
SetLapTime<public>(Agent:agent):void |
Sets the lap time indicator for Agent. |
SetLapTimeForAll |
SetLapTimeForAll<public>(Agent:agent):void |
Sets the lap time indicator for all agents. |
SetLapTimeForAll |
SetLapTimeForAll<public>():void |
Sets the lap time indicator for all agents. |
SetMaxDuration |
SetMaxDuration<public>(Time:float):void |
Sets the maximum duration of the timer (in seconds). |
GetMaxDuration |
GetMaxDuration<public>()<transacts>:float |
Returns the maximum duration of the timer (in seconds). |
IsStatePerAgent |
IsStatePerAgent<public>()<transacts><decides>:void |
Succeeds if this device is tracking timer state for each individual agent independently. Fails if state is being tracked globally for all agent's. |
Walkthrough
Scenario: The Clifftop Signal Race
A bright sunny Fortnite island. Players spawn on a clifftop dock overlooking a sparkling cove. They have 60 seconds to interact with three signal flares scattered along the shore. When all three are lit, the timer is force-completed (success). If time runs out first, the failure path fires. At the 15-second mark, urgency mode kicks in and the sky dims.
This single device class wires up all three events, starts the timer on begin, and demonstrates Start, Complete, ResetForAll, and SetActiveDuration.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Characters }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# Place this creative_device on your island, then assign the
# timer_device and three button_devices in the Details panel.
clifftop_signal_race := class(creative_device):
# ── Editable device references ──────────────────────────────
@editable
RaceTimer : timer_device = timer_device{}
# Three signal-flare buttons placed along the shore
@editable
Flare1 : button_device = button_device{}
@editable
Flare2 : button_device = button_device{}
@editable
Flare3 : button_device = button_device{}
# ── Internal state ──────────────────────────────────────────
var FlaresLit : int = 0
# ── Lifecycle ───────────────────────────────────────────────
OnBegin<override>()<suspends> : void =
# Subscribe to all three timer events
RaceTimer.SuccessEvent.Subscribe(OnRaceSuccess)
RaceTimer.FailureEvent.Subscribe(OnRaceFailure)
RaceTimer.StartUrgencyModeEvent.Subscribe(OnUrgency)
# Subscribe to each flare button
Flare1.InteractedWithEvent.Subscribe(OnFlareLit)
Flare2.InteractedWithEvent.Subscribe(OnFlareLit)
Flare3.InteractedWithEvent.Subscribe(OnFlareLit)
# Give the timer a 60-second window and start it for everyone
if (FirstPlayer := GetPlayspace().GetPlayers()[0]):
RaceTimer.SetActiveDuration(60.0, FirstPlayer)
RaceTimer.StartForAll()
# ── Flare handler ────────────────────────────────────────────
# Called whenever any flare button is pressed.
OnFlareLit(Agent : agent) : void =
set FlaresLit = FlaresLit + 1
if (FlaresLit >= 3):
# All flares lit — force a success for everyone
RaceTimer.CompleteForAll()
# ── Timer event handlers ─────────────────────────────────────
OnRaceSuccess(Agent : ?agent) : void =
# The timer was completed — players lit all three flares in time!
# (Trigger your fireworks sequence device here)
Print("Success! All signal flares lit.")
OnRaceFailure(Agent : ?agent) : void =
# Time expired before all flares were lit
Print("Failure! The tide came in.")
# Reset for a rematch
set FlaresLit = 0
RaceTimer.ResetForAll()
OnUrgency(Agent : ?agent) : void =
# Timer entered urgency mode (configured in device settings, e.g. last 15 s)
# Trigger a storm-cloud prop or audio device here
Print("Urgency! Storm approaching the cove!")```
### Line-by-line breakdown
| Lines | What's happening |
|---|---|
| `@editable` fields | Expose the `timer_device` and three `button_device`s to the Details panel so you can drag your placed devices in. |
| `var FlaresLit` | Simple counter tracking how many flares the players have activated. |
| `RaceTimer.SuccessEvent.Subscribe(...)` | Registers `OnRaceSuccess` to fire whenever the timer is completed. |
| `RaceTimer.FailureEvent.Subscribe(...)` | Registers `OnRaceFailure` to fire when the countdown hits zero. |
| `RaceTimer.StartUrgencyModeEvent.Subscribe(...)` | Registers `OnUrgency` for the final-stretch warning. |
| `RaceTimer.SetActiveDuration(60.0, ...)` | Overrides the timer's remaining time to exactly 60 seconds for one agent (used here as a setup call before `StartForAll`). |
| `RaceTimer.StartForAll()` | Kicks off the countdown on every player's HUD simultaneously. |
| `RaceTimer.CompleteForAll()` | When all flares are lit, force-succeeds the timer for every player at once. |
| `RaceTimer.ResetForAll()` | On failure, rewinds the timer to its base duration so a rematch can begin. |
| `(Agent : ?agent)` handlers | All three event handlers receive `?agent` (optional). Unwrap with `if (A := Agent?):` before calling agent-specific APIs. |
---
## Common patterns
### Pattern 1 — Per-player timer with Pause and Resume
A dock diving challenge: pause the timer while a player is underwater (tracked by a trigger volume), resume when they surface.
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
dive_challenge := class(creative_device):
@editable
DiveTimer : timer_device = timer_device{}
# Trigger volume placed at the water surface
@editable
WaterSurface : trigger_device = trigger_device{}
# Trigger volume placed at the seafloor
@editable
SeafloorZone : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
DiveTimer.SuccessEvent.Subscribe(OnDiveComplete)
DiveTimer.FailureEvent.Subscribe(OnDiveTimeout)
# Player dives — pause the timer so only active dive time counts
WaterSurface.TriggeredEvent.Subscribe(OnPlayerDived)
# Player surfaces — resume the countdown
SeafloorZone.TriggeredEvent.Subscribe(OnPlayerSurfaced)
DiveTimer.Start()
OnPlayerDived(Agent : ?agent) : void =
if (A := Agent?):
# Pause the countdown for this specific player while submerged
DiveTimer.Pause(A)
OnPlayerSurfaced(Agent : ?agent) : void =
if (A := Agent?):
# Resume their personal countdown when they come back up
DiveTimer.Resume(A)
OnDiveComplete(Agent : ?agent) : void =
Print("Dive complete — treasure found!")
OnDiveTimeout(Agent : ?agent) : void =
Print("Ran out of air!")
if (A := Agent?):
DiveTimer.ResetForAll(A)
Pattern 2 — Dynamic time injection with SetActiveDuration
A cove scavenger hunt where picking up a bonus chest adds 15 extra seconds to the clock.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
cove_scavenger_hunt := class(creative_device):
@editable
HuntTimer : timer_device = timer_device{}
# Bonus chest button — grants extra time when interacted with
@editable
BonusChest : button_device = button_device{}
# Base hunt duration in seconds
BaseDuration : float = 45.0
# Bonus seconds awarded per chest
BonusSeconds : float = 15.0
OnBegin<override>()<suspends> : void =
HuntTimer.FailureEvent.Subscribe(OnHuntFailed)
HuntTimer.SuccessEvent.Subscribe(OnHuntWon)
BonusChest.InteractedWithEvent.Subscribe(OnBonusChestOpened)
HuntTimer.StartForAll()
OnBonusChestOpened(Agent : ?agent) : void =
if (A := Agent?):
# Read current remaining time and add the bonus
CurrentTime := HuntTimer.GetActiveDuration(A)
NewTime := CurrentTime + BonusSeconds
HuntTimer.SetActiveDuration(NewTime, A)
OnHuntFailed(Agent : ?agent) : void =
Print("Hunt failed — the cove treasure sank!")
OnHuntWon(Agent : ?agent) : void =
Print("Hunt complete — treasure secured!")
Pattern 3 — Enable/Disable guarding the timer
A shore relay race: the timer device is disabled at startup and only enabled once the starting gun fires (a button press by the host). This prevents players from accidentally triggering it during setup.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
shore_relay_race := class(creative_device):
@editable
RelayTimer : timer_device = timer_device{}
# Host presses this button to fire the starting gun
@editable
StartGunButton : button_device = button_device{}
OnBegin<override>()<suspends> : void =
# Timer is disabled in the Details panel by default;
# guard it here too so no stray signals reach it
RelayTimer.Disable()
RelayTimer.SuccessEvent.Subscribe(OnRelayFinished)
RelayTimer.FailureEvent.Subscribe(OnRelayTimeout)
RelayTimer.StartUrgencyModeEvent.Subscribe(OnFinalLap)
StartGunButton.InteractedWithEvent.Subscribe(OnStartGunFired)
OnStartGunFired(Agent : ?agent) : void =
# Enable the timer so it can receive Start signals,
# then kick it off for the whole lobby
RelayTimer.Enable()
RelayTimer.StartForAll()
OnFinalLap(Agent : ?agent) : void =
# Urgency mode hit — play a dramatic horn sound via an audio device
Print("Final lap! Urgency mode active.")
OnRelayFinished(Agent : ?agent) : void =
Print("Relay complete!")
RelayTimer.Disable()
OnRelayTimeout(Agent : ?agent) : void =
Print("Time expired — relay failed.")
RelayTimer.ResetForAll()
Gotchas
1. All three event handlers receive ?agent, not agent
SuccessEvent, FailureEvent, and StartUrgencyModeEvent are all typed listenable(?agent). Your handler signature must be (Agent : ?agent) : void. If you try to call any agent-specific API directly on Agent, the compiler will reject it — always unwrap first:
# CORRECT
OnRaceSuccess(Agent : ?agent) : void =
if (A := Agent?):
# Now A is a concrete agent — safe to use
RaceTimer.Complete(A)
2. SetActiveDuration only affects an active timer
The method sets the remaining time on a currently-running timer. Calling it before Start or after the timer has already stopped has no effect. Always call Start (or StartForAll) before injecting dynamic time.
3. CompleteForAll fires SuccessEvent, not FailureEvent
Calling CompleteForAll() or Complete(Agent) triggers SuccessEvent. Only a natural countdown-to-zero triggers FailureEvent. Keep this in mind when designing your win/lose logic.
4. Disable blocks ALL signals — including your own Start calls
If you call RelayTimer.Disable() and then immediately call RelayTimer.Start(), the start is silently ignored. Always Enable() before Start().
5. ResetForAll stops AND rewinds — it does not restart
After ResetForAll(), the timer is stopped at its base duration. You must call Start() or StartForAll() again to begin a new countdown.
6. Per-agent vs. global methods
Methods like Pause(Agent) and Resume(Agent) affect only that one player's timer state. Methods like PauseForAll() affect everyone. Mixing the two in the same session can lead to players being out of sync — pick one model per game mode and stick to it.
7. message parameters elsewhere in your island
If you're using timer_device alongside any device that takes a message parameter (like hud_message_device), remember that Verse does not accept raw strings where message is expected. Declare a localizer function:
TimerLabel<localizes>(S : string) : message = "{S}"
# Then pass: TimerLabel("Shore Race")