Overview
The instrument_player_device sits inside the Patchwork audio system. Patchwork lets you build in-game music by routing note triggers through instruments and effects. The instrument_player_device is the instrument layer — it receives note data and turns it into sampled audio.
From Verse you have two levers:
| What you want | Call |
|---|---|
| Start letting notes through (instrument active) | Enable() |
| Silence the instrument (notes ignored) | Disable() |
When to reach for it:
- Dynamic music that reacts to game state (combat starts → instrument enabled, combat ends → instrument disabled).
- Puzzle rooms where solving a puzzle "unlocks" a musical layer.
- Timed challenges where the music drops out when time expires.
- Any Patchwork composition where you want Verse — not the editor timeline — to control which instruments are live.
API Reference
instrument_player_device
Turn Patchwork note inputs into audio using instrument samples.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from patchwork_device.
instrument_player_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: The Arena Boss Fight
You have a boss arena. When a player steps on a pressure plate, the boss spawns and an intense instrument layer kicks in. When the round ends (a second trigger fires), the instrument is silenced. A trigger_device named BossSpawnTrigger starts the fight; another named RoundEndTrigger ends it.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
# Drop this device into your level from the Content Browser,
# then wire up the three @editable references in the Details panel.
boss_music_controller := class(creative_device):
# The Patchwork instrument you want to control.
@editable
Instrument : instrument_player_device = instrument_player_device{}
# A trigger_device placed at the boss arena entrance.
@editable
BossSpawnTrigger : trigger_device = trigger_device{}
# A trigger_device wired to your round-end logic.
@editable
RoundEndTrigger : trigger_device = trigger_device{}
# Called automatically when the experience starts.
OnBegin<override>()<suspends> : void =
# Make sure the instrument is silent at the start of the round.
Instrument.Disable()
# Subscribe to both triggers so we react whenever they fire.
BossSpawnTrigger.TriggeredEvent.Subscribe(OnBossSpawned)
RoundEndTrigger.TriggeredEvent.Subscribe(OnRoundEnd)
# Handler: a player stepped on the boss spawn plate.
# trigger_device.TriggeredEvent sends ?agent, so we accept that type.
OnBossSpawned(Agent : ?agent) : void =
# Enable the instrument — Patchwork notes now produce audio.
Instrument.Enable()
# Handler: the round-end trigger fired.
OnRoundEnd(Agent : ?agent) : void =
# Disable the instrument — notes are ignored, music goes silent.
Instrument.Disable()
Line-by-line breakdown:
@editablefields — Every placed device must be declared as an@editablefield. You cannot reference a scene device any other way in Verse.OnBegin— The entry point for all Verse creative devices. We callInstrument.Disable()immediately so the instrument doesn't bleed audio before the fight starts.Subscribe— We attach our handler methods toTriggeredEventon each trigger. The event fires whenever a player activates the trigger.OnBossSpawned— CallsInstrument.Enable(). From this moment, any Patchwork note routed to this instrument will produce sound.OnRoundEnd— CallsInstrument.Disable(). Notes are now ignored; the instrument layer goes dark.Agent : ?agent—trigger_device.TriggeredEventis alistenable(?agent). We accept the optional agent but don't need to unwrap it here because our logic doesn't depend on which player fired the trigger.
Common patterns
Pattern 1 — Enable on game start, Disable when time runs out
A countdown timer device signals when time expires. The instrument plays throughout the round and cuts when the clock hits zero.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
timed_music_controller := class(creative_device):
@editable
Instrument : instrument_player_device = instrument_player_device{}
# A timer_device set to count down the round length.
@editable
RoundTimer : timer_device = timer_device{}
OnBegin<override>()<suspends> : void =
# Music is live from the first second of the round.
Instrument.Enable()
# timer_device.SuccessEvent fires when the timer reaches zero.
RoundTimer.SuccessEvent.Subscribe(OnTimerExpired)
OnTimerExpired(Agent : ?agent) : void =
# Time's up — cut the instrument.
Instrument.Disable()
Pattern 2 — Toggle the instrument each time a button is pressed
A button in a music room lets players switch an instrument layer on and off interactively.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
music_toggle_controller := class(creative_device):
@editable
Instrument : instrument_player_device = instrument_player_device{}
@editable
ToggleButton : button_device = button_device{}
# Track whether the instrument is currently active.
var IsEnabled : logic = false
OnBegin<override>()<suspends> : void =
# Start disabled.
Instrument.Disable()
ToggleButton.InteractedWithEvent.Subscribe(OnButtonPressed)
OnButtonPressed(Agent : agent) : void =
if (IsEnabled?):
# Currently on — turn it off.
Instrument.Disable()
set IsEnabled = false
else:
# Currently off — turn it on.
Instrument.Enable()
set IsEnabled = true
Note:
button_device.InteractedWithEventis alistenable(agent)(not optional), so the handler takesAgent : agentdirectly — no unwrapping needed.
Pattern 3 — Enable for one player's team, Disable for the other
In a two-team game, each team has its own instrument layer. When Team 1 captures a zone, their instrument enables and Team 2's disables.
using { /Fortnite.com/Devices }
using { /Fortnite.com/Devices/Patchwork }
using { /Verse.org/Simulation }
team_music_controller := class(creative_device):
@editable
Team1Instrument : instrument_player_device = instrument_player_device{}
@editable
Team2Instrument : instrument_player_device = instrument_player_device{}
# A capture_area_device that signals when Team 1 owns the zone.
@editable
CaptureZone : capture_area_device = capture_area_device{}
OnBegin<override>()<suspends> : void =
# Neither team has the zone at start.
Team1Instrument.Disable()
Team2Instrument.Disable()
# capture_area_device.TeamScoresEvent fires with the scoring team's agent.
CaptureZone.TeamScoresEvent.Subscribe(OnZoneCaptured)
OnZoneCaptured(Agent : agent) : void =
# For this example we simply enable Team1's layer on any capture.
# In a full build you'd check the agent's team here.
Team1Instrument.Enable()
Team2Instrument.Disable()
Gotchas
1. instrument_player_device extends patchwork_device — place it correctly
The device lives in the Patchwork category of the Content Browser, not the general Devices panel. If you can't find it, search "Instrument Player" in the UEFN Content Browser.
2. @editable is mandatory
You cannot write instrument_player_device{}.Enable() as a standalone expression and expect it to control a placed device. The @editable field is the bridge between your Verse class and the actual device sitting in your level. Without it, you're operating on a default-constructed object that has no scene presence.
3. Disable does not reset Patchwork state
Disable() stops the instrument from responding to new notes — it does not flush notes already queued in the Patchwork graph. If you hear a brief tail after calling Disable(), that is expected Patchwork behaviour; the note pipeline drains naturally.
4. No events on this device
instrument_player_device exposes no events of its own. You cannot subscribe to "instrument started playing" or "note received." All reactive logic must come from other devices (triggers, buttons, timers) that you subscribe to in Verse, then call Enable/Disable in response.
5. trigger_device.TriggeredEvent sends ?agent, not agent
When you subscribe a handler to TriggeredEvent, the payload is ?agent (an optional). If your handler logic needs the actual agent (e.g., to check their team), unwrap it first:
OnTriggered(MaybeAgent : ?agent) : void =
if (A := MaybeAgent?):
# A is now a confirmed agent — safe to use.
_ = A # replace with real logic
Failing to unwrap and passing ?agent where agent is expected is a compile error.
6. Calling Enable() on an already-enabled device (or Disable() on an already-disabled one) is safe
These calls are idempotent — no error, no double-trigger. You can call them freely without tracking prior state unless your game logic specifically needs to know the current state (as in the toggle pattern above).