Reference Verse compiles

timer_device: Countdown Timers That Drive Your Game

The `timer_device` is your island's built-in clock — it counts down, screams urgency, and fires success or failure events so your Verse code can react instantly. Whether you're racing to light signal flares before a storm rolls in off the cove, or giving players 90 seconds to collect treasure chests on a clifftop, the timer_device handles the display and the events while your Verse handles the consequences.

Updated Examples verified on the live UEFN compiler
Watch the Knottimer_device in ~90 seconds.

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")

Guides & scripts that use timer_device

Step-by-step tutorials that put this object to work.

Build your own lesson with timer_device

Generate a personalized, step-by-step lesson plan built around this object — grounded in this exact reference and our compile-verified knowledge base.

Build a lesson →