Overview
The air_vent_device is a Creative device that applies an upward boost to any agent, vehicle, or physics object that enters its area. Out of the box it works as a static launch pad, but wiring it to Verse unlocks three superpowers:
Enable/Disable— toggle whether the vent can be triggered at all (great for timed hazards or locked zones).Activate— fire the vent's boost right now, regardless of whether a player is standing on it (useful for scripted sequences or remote triggers).
Reach for air_vent_device when you need launch pads that react to game events: a vault that ejects intruders, a timed gauntlet that alternates which vents are live, or a cinematic moment where the floor launches the player into the sky.
API Reference
air_vent_device
Used to boost
agents, vehicles, and other objects upwards into the air.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).
air_vent_device<public> := class<concrete><final>(creative_device_base):
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
Activate |
Activate<public>():void |
Activates this device. |
Walkthrough
Scenario: A timed gauntlet room. When the round starts, all vents are disabled. A countdown timer (simulated with Sleep) enables the vents one by one. When a player steps on a trigger_device marked "Escape", the escape vent fires immediately via Activate and all other vents shut off.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# Place this device in your level and wire up the @editable fields in the Details panel.
gauntlet_vent_controller := class(creative_device):
# The main launch vent in the centre of the room — starts disabled.
@editable
CentreVent : air_vent_device = air_vent_device{}
# A side vent that activates after a delay.
@editable
SideVent : air_vent_device = air_vent_device{}
# The escape vent — fires on demand when the player hits the escape trigger.
@editable
EscapeVent : air_vent_device = air_vent_device{}
# A trigger the player steps on to call the escape sequence.
@editable
EscapeTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
# 1. Disable all vents at round start so the room is safe to enter.
CentreVent.Disable()
SideVent.Disable()
EscapeVent.Disable()
# 2. Subscribe to the escape trigger BEFORE the countdown starts
# so we never miss the event.
EscapeTrigger.TriggeredEvent.Subscribe(OnEscapeTriggered)
# 3. After 5 seconds, enable the centre vent — the gauntlet begins.
Sleep(5.0)
CentreVent.Enable()
# 4. Three seconds later, the side vent joins the chaos.
Sleep(3.0)
SideVent.Enable()
# 5. Keep the gauntlet running for another 10 seconds, then reset.
Sleep(10.0)
CentreVent.Disable()
SideVent.Disable()
# Called when the player steps on the escape trigger plate.
# trigger_device.TriggeredEvent sends ?agent, so we accept that type.
OnEscapeTriggered(Agent : ?agent) : void =
# Shut down the hazard vents immediately.
CentreVent.Disable()
SideVent.Disable()
# Enable the escape vent, then fire it right now.
EscapeVent.Enable()
EscapeVent.Activate() # Launches the player even if they aren't standing on it yet.
Line-by-line breakdown:
| Lines | What's happening |
|---|---|
@editable fields |
Exposes each air_vent_device (and the trigger) to the UEFN Details panel so you can drag-assign placed devices without touching code. |
CentreVent.Disable() × 3 |
Ensures all vents are inert when the round begins — no accidental launches during setup. |
EscapeTrigger.TriggeredEvent.Subscribe(OnEscapeTriggered) |
Registers the handler before the Sleep calls so no trigger event is missed during the countdown. |
Sleep(5.0) |
Suspends execution for 5 real seconds — OnBegin must carry <suspends> for this to compile. |
CentreVent.Enable() |
Turns the centre vent on; players who walk over it will now be launched. |
EscapeVent.Activate() |
Fires the vent's boost immediately — this is the key difference from Enable: Activate triggers the launch right now rather than waiting for a player to step on it. |
Common patterns
Pattern 1 — Toggling a vent with a button
A simple on/off switch: one button enables the vent, another disables it. Great for puzzle rooms where players control their own launch pad.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
vent_toggle_device := class(creative_device):
@editable
LaunchVent : air_vent_device = air_vent_device{}
@editable
EnableButton : button_device = button_device{}
@editable
DisableButton : button_device = button_device{}
OnBegin<override>()<suspends> : void =
# Vent starts disabled — players must press the button to arm it.
LaunchVent.Disable()
EnableButton.InteractedWithEvent.Subscribe(OnEnablePressed)
DisableButton.InteractedWithEvent.Subscribe(OnDisablePressed)
OnEnablePressed(Agent : agent) : void =
LaunchVent.Enable()
OnDisablePressed(Agent : agent) : void =
LaunchVent.Disable()
Key point: Enable and Disable are plain void calls with no effects — call them freely from any handler without <suspends>.
Pattern 2 — Scripted launch sequence (Activate)
A cinematic moment: after a boss is defeated, the floor vents fire in a wave to launch all players into the victory arena. Activate fires each vent in sequence with a short delay between them.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
boss_defeat_launcher := class(creative_device):
@editable
BossDefeatTrigger : trigger_device = trigger_device{}
@editable
VentA : air_vent_device = air_vent_device{}
@editable
VentB : air_vent_device = air_vent_device{}
@editable
VentC : air_vent_device = air_vent_device{}
OnBegin<override>()<suspends> : void =
BossDefeatTrigger.TriggeredEvent.Subscribe(OnBossDefeated)
OnBossDefeated(Agent : ?agent) : void =
# Spawn an async task so the handler returns immediately
# while the wave sequence runs in the background.
spawn { RunLaunchWave() }
RunLaunchWave()<suspends> : void =
# Enable all vents first so Activate has something to fire.
VentA.Enable()
VentA.Activate()
Sleep(0.4)
VentB.Enable()
VentB.Activate()
Sleep(0.4)
VentC.Enable()
VentC.Activate()
Key point: Event handlers cannot be <suspends>, so use spawn { } to run any async wave logic without blocking the event system.
Pattern 3 — Alternating hazard vents
Two vents take turns being active — classic platformer obstacle. Players must time their crossing.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
alternating_vents_device := class(creative_device):
@editable
VentLeft : air_vent_device = air_vent_device{}
@editable
VentRight : air_vent_device = air_vent_device{}
# How long each vent stays active, in seconds.
@editable
ActiveDuration : float = 2.5
OnBegin<override>()<suspends> : void =
# Start with both off.
VentLeft.Disable()
VentRight.Disable()
# Alternate forever.
loop:
VentLeft.Enable()
VentRight.Disable()
Sleep(ActiveDuration)
VentLeft.Disable()
VentRight.Enable()
Sleep(ActiveDuration)
Key point: loop with Sleep is the idiomatic Verse pattern for repeating timed behaviour. Because OnBegin is <suspends>, the Sleep calls work without any extra setup.
Gotchas
1. Always declare devices as @editable fields
You cannot write air_vent_device{}.Enable() inline — that creates a new default instance, not the one you placed in your level. Every device reference must be an @editable field assigned in the UEFN Details panel.
# ❌ Wrong — operates on a throwaway instance, does nothing in-game
air_vent_device{}.Enable()
# ✅ Correct — operates on the placed device
@editable
MyVent : air_vent_device = air_vent_device{}
# ... then call MyVent.Enable()
2. Activate ≠ Enable
Enablearms the vent so it launches objects that enter its area.Activatefires the boost immediately — but the vent must already be enabled for the launch to work on players standing on it. When usingActivatefor scripted sequences, callEnablefirst.- A disabled vent that receives
Activatemay not launch players — always pair them.
3. Event handlers cannot <suspends>
If you need Sleep inside an event handler (e.g., OnEscapeTriggered), you must spawn a separate async function:
# ❌ Won't compile — handlers can't suspend
OnEscapeTriggered(Agent : ?agent)<suspends> : void =
Sleep(1.0)
EscapeVent.Activate()
# ✅ Correct — spawn an async coroutine
OnEscapeTriggered(Agent : ?agent) : void =
spawn { DelayedActivate() }
DelayedActivate()<suspends> : void =
Sleep(1.0)
EscapeVent.Activate()
4. trigger_device.TriggeredEvent sends ?agent, not agent
The event payload is an optional agent. If your handler receives ?agent and you need to act on the specific player, unwrap it first:
OnTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
# A is a confirmed agent here
Print("Agent triggered the vent")
5. Disable does not reset mid-air players
Calling Disable stops the vent from launching future entrants. Any player already mid-air from a previous launch is unaffected — physics takes over once they leave the vent's influence area.