Overview
The speaker_device is a Patchwork audio output device — it plays whatever audio asset you've wired up in the UEFN editor and exposes two Verse methods: Enable and Disable. That's the whole surface, and it's all you need.
When to reach for it:
- You want background music or ambient sound that starts or stops based on gameplay events (zone capture, boss spawn, round start/end).
- You need to mute a speaker when a player enters a "silent zone" and restore it when they leave.
- You want to stagger multiple audio layers — e.g., bring in a bass track when combat intensity rises.
speaker_device inherits from patchwork_device and lives in the /Fortnite.com/Devices/Patchwork module, so you'll need that import alongside the standard /Fortnite.com import.
API Reference
speaker_device
Output Patchwork audio for players to hear.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from patchwork_device.
speaker_device<public> := class<concrete><final>(patchwork_device):
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. |
Walkthrough
Scenario: A capture-point map. When the round starts, eerie ambient music plays. The moment a player steps on the capture plate, the ambient music cuts out and a tense combat sting kicks in. When the player leaves the plate, the ambient music resumes and the combat sting silences.
Place two speaker_device actors in your level (one for ambient, one for combat), a trigger_device set to fire on player enter, and a second trigger for player exit. Wire them all to this Verse device.
using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
# capture_audio_manager
# Swaps between ambient and combat audio when a player
# steps onto (or off) the capture plate.
capture_audio_manager := class(creative_device):
# Drag your ambient speaker device here in the Details panel
@editable
AmbientSpeaker : speaker_device = speaker_device{}
# Drag your combat sting speaker device here
@editable
CombatSpeaker : speaker_device = speaker_device{}
# Trigger placed on the capture plate — fires when a player enters
@editable
EnterTrigger : trigger_device = trigger_device{}
# Trigger placed on the capture plate — fires when a player exits
@editable
ExitTrigger : trigger_device = trigger_device{}
# Entry point — subscribe to both triggers, start ambient music
OnBegin<override>()<suspends> : void =
# Ambient music plays from the moment the round begins
AmbientSpeaker.Enable()
# Combat sting starts silent
CombatSpeaker.Disable()
# Subscribe to plate enter/exit events
EnterTrigger.TriggeredEvent.Subscribe(OnPlayerEnterPlate)
ExitTrigger.TriggeredEvent.Subscribe(OnPlayerExitPlate)
# Called when any player steps onto the capture plate
OnPlayerEnterPlate(Agent : ?agent) : void =
# Silence the ambient track — tension rises
AmbientSpeaker.Disable()
# Bring in the combat sting
CombatSpeaker.Enable()
# Called when the player leaves the capture plate
OnPlayerExitPlate(Agent : ?agent) : void =
# Combat sting fades out
CombatSpeaker.Disable()
# Ambient music resumes
AmbientSpeaker.Enable()
Line-by-line breakdown:
| Lines | What's happening |
|---|---|
@editable fields |
Expose both speakers and both triggers to the UEFN Details panel so you can assign real placed devices without hardcoding. |
AmbientSpeaker.Enable() in OnBegin |
Starts ambient audio immediately when the round begins. |
CombatSpeaker.Disable() in OnBegin |
Ensures the combat sting is silent at round start — even if the device's "Start Enabled" property is checked in the editor, this guarantees the correct initial state from code. |
EnterTrigger.TriggeredEvent.Subscribe(OnPlayerEnterPlate) |
Registers the handler; TriggeredEvent fires a listenable(?agent) so the handler receives Agent : ?agent. |
AmbientSpeaker.Disable() / CombatSpeaker.Enable() |
The audio swap — one line each, no async needed. |
OnPlayerExitPlate |
Reverses the swap when the plate is vacated. |
Editor setup: In UEFN, place two
Speakerdevices, set each to a different Patchwork audio asset. Set Start Enabled to Off on both — Verse owns the initial state. Place twoTriggerdevices on the capture zone boundary (one for enter, one for exit). Assign all four devices to the Verse device's editable fields.
Common patterns
Pattern 1 — Round-gated music (Enable on round start, Disable on round end)
Use fort_round_manager to tie speaker state directly to round lifecycle.
using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
# round_music_manager
# Plays a speaker only while a Fortnite round is active.
round_music_manager := class(creative_device):
@editable
RoundSpeaker : speaker_device = speaker_device{}
OnBegin<override>()<suspends> : void =
# Silence the speaker until a round actually starts
RoundSpeaker.Disable()
# GetFortRoundManager can fail (decides), so use 'if'
if (RoundMgr := GetFortRoundManager[]):
# SubscribeRoundStarted fires immediately if a round is already running
RoundMgr.SubscribeRoundStarted(OnRoundStarted)
RoundMgr.SubscribeRoundEnded(OnRoundEnded)
# Async callback — must be suspends to satisfy SubscribeRoundStarted
OnRoundStarted()<suspends> : void =
RoundSpeaker.Enable()
OnRoundEnded() : void =
RoundSpeaker.Disable()
Note:
GetFortRoundManageris an extension method onentitythat uses<transacts><decides>, so it must be called inside anifexpression.SubscribeRoundStartedrequires a<suspends>callback — match that signature exactly.
Pattern 2 — Button-toggled speaker (Enable / Disable alternating)
A simple on/off toggle: press a button to silence or restore a speaker.
using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
# speaker_toggle_device
# A button that alternates a speaker between enabled and disabled.
speaker_toggle_device := class(creative_device):
@editable
ToggleButton : button_device = button_device{}
@editable
TargetSpeaker : speaker_device = speaker_device{}
# Track current state
var SpeakerOn : logic = true
OnBegin<override>()<suspends> : void =
# Speaker starts enabled
TargetSpeaker.Enable()
ToggleButton.InteractedWithEvent.Subscribe(OnButtonPressed)
OnButtonPressed(Agent : agent) : void =
if (SpeakerOn?):
TargetSpeaker.Disable()
set SpeakerOn = false
else:
TargetSpeaker.Enable()
set SpeakerOn = true
Pattern 3 — Multi-speaker zone reveal (Enable a bank of speakers at once)
A cinematic moment: when a player triggers a cutscene zone, silence all ambient speakers and enable the cinematic score.
using { /Fortnite.com }
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
# cinematic_audio_director
# Silences ambient speakers and activates the cinematic score
# when a player enters the boss arena trigger.
cinematic_audio_director := class(creative_device):
# Up to three ambient speakers to silence
@editable
AmbientA : speaker_device = speaker_device{}
@editable
AmbientB : speaker_device = speaker_device{}
@editable
AmbientC : speaker_device = speaker_device{}
# The dramatic boss-arena score
@editable
BossScore : speaker_device = speaker_device{}
@editable
ArenaTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
AmbientA.Enable()
AmbientB.Enable()
AmbientC.Enable()
BossScore.Disable()
ArenaTrigger.TriggeredEvent.Subscribe(OnArenaEntered)
OnArenaEntered(Agent : ?agent) : void =
# Kill all ambient layers
AmbientA.Disable()
AmbientB.Disable()
AmbientC.Disable()
# Unleash the boss score
BossScore.Enable()
Gotchas
1. speaker_device is in the Patchwork module — don't forget the import
The type lives under /Fortnite.com/Devices/Patchwork, not the standard /Fortnite.com/Devices. If you omit using { /Fortnite.com/Devices/Patchwork } you'll get an Unknown identifier error on speaker_device. Always include both imports.
2. Enable / Disable are fire-and-forget — no return value, no await
Both methods return void and have no <suspends> effect, so you call them as plain statements. You do not need to await them or call them inside a spawn block. They take effect immediately on the game thread.
3. Editor "Start Enabled" vs. Verse initial state
If you set Start Enabled = On in the UEFN Details panel and call Disable() in OnBegin, Verse wins — the device will be disabled at runtime. Be explicit: always set the initial state in OnBegin so the code is the single source of truth, regardless of editor settings.
4. No events — you must drive it from another device's event
speaker_device has no events of its own. It cannot tell you when audio starts or stops. All logic must be driven by external events (triggers, buttons, round manager, etc.). If you need audio-completion callbacks, you'll need a timer or a separate signaling device.
5. trigger_device.TriggeredEvent hands you ?agent, not agent
If your handler needs the agent who triggered the event, unwrap the option first:
OnTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
# use A as a concrete agent here
SomeSpeaker.Enable()
Forgetting the unwrap and trying to use MaybeAgent directly as an agent is a compile error.