Overview
The note_trigger_device is a Patchwork device — part of the music/audio toolkit in UEFN. It listens to note inputs coming from other Patchwork devices (sequencers, synthesizers, the Patchwork graph) and sends out an event whenever its configured note fires. Think of it as the bridge between music and gameplay: every kick drum can pop a balloon, every melody note can flicker a light, every beat can advance a puzzle.
In Verse, note_trigger_device inherits from patchwork_device, so its scripting surface is intentionally small: you can Enable and Disable it. That means you control when the music is allowed to drive your game — turn the note trigger off during a cutscene, back on when the boss fight starts.
Because the note trigger's outputs are wired through the device-binding panel (its events route to other devices in the editor), the common pattern is: Verse owns a regular trigger_device for the rich rhythm logic (trigger counts, reset delays, the TriggeredEvent), and Enable/Disable the note_trigger_device to gate when music can participate. Reach for this device whenever you want gameplay that feels choreographed to the soundtrack.
API Reference
note_trigger_device
Send events to devices based on Patchwork note inputs.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from patchwork_device.
note_trigger_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. |
trigger_device
Used to relay events to other linked devices.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from trigger_base_device.
trigger_device<public> := class<concrete><final>(trigger_base_device):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
TriggeredEvent |
TriggeredEvent<public>:listenable(?agent) |
Signaled when an agent triggers this device. Sends the agent that used this device. Returns false if no agent triggered the action (ex: it was triggered through code). |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Trigger |
Trigger<public>(Agent:agent):void |
Triggers this device with Agent being passed as the agent that triggered the action. Use an agent reference when this device is setup to require one (for instance, you want to trigger the device only with a particular agent. |
Trigger |
Trigger<public>():void |
Triggers this device, causing it to activate its TriggeredEvent event. |
Enable |
Enable<public>():void |
Enables this device. |
Disable |
Disable<public>():void |
Disables this device. |
SetMaxTriggerCount |
SetMaxTriggerCount<public>(MaxCount:int):void |
Sets the maximum amount of times this device can trigger. * 0 can be used to indicate no limit on trigger count. * MaxCount is clamped between [0,20]. |
GetMaxTriggerCount |
GetMaxTriggerCount<public>()<transacts>:int |
Gets the maximum amount of times this device can trigger. * 0 indicates no limit on trigger count. |
GetTriggerCountRemaining |
GetTriggerCountRemaining<public>()<transacts>:int |
Returns the number of times that this device can still be triggered before hitting GetMaxTriggerCount. Returns 0 if GetMaxTriggerCount is unlimited. |
SetResetDelay |
SetResetDelay<public>(Time:float):void |
Sets the time (in seconds) after triggering, before the device can be triggered again (if MaxTrigger count allows). |
GetResetDelay |
GetResetDelay<public>()<transacts>:float |
Gets the time (in seconds) before the device can be triggered again (if MaxTrigger count allows). |
SetTransmitDelay |
SetTransmitDelay<public>(Time:float):void |
Sets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered. |
GetTransmitDelay |
GetTransmitDelay<public>()<transacts>:float |
Gets the time (in seconds) which must pass after triggering, before this device informs other external devices that it has been triggered. |
Walkthrough
The scenario: A rhythm arena. While the track plays, every beat fires a note_trigger_device, which in the editor is wired to call a trigger_device. Verse listens to that trigger's TriggeredEvent to flash a light / award points, but only lets the beats land 8 times before a short rest. When a player steps on a start plate, we Enable the note trigger so the music begins driving the room; the rest of the timing is configured on the trigger_device.
rhythm_arena_device := class(creative_device):
# The Patchwork note trigger — fires on each musical note. We gate it on/off.
@editable
NoteTrigger : note_trigger_device = note_trigger_device{}
# A regular trigger wired (in editor) to the note trigger's output.
# We own its rhythm logic in Verse.
@editable
BeatTrigger : trigger_device = trigger_device{}
# Player steps here to start the rhythm sequence.
@editable
StartPlate : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
# Don't let the music drive anything until a player starts the round.
NoteTrigger.Disable()
# Configure the beat trigger: allow 8 beats, then a 2s rest, no transmit lag.
BeatTrigger.SetMaxTriggerCount(8)
BeatTrigger.SetResetDelay(2.0)
BeatTrigger.SetTransmitDelay(0.0)
# React to each beat.
BeatTrigger.TriggeredEvent.Subscribe(OnBeat)
# React to a player stepping on the start plate.
StartPlate.TriggeredEvent.Subscribe(OnStart)
# Player stepped on the start plate -> let the music begin driving the room.
OnStart(Agent : ?agent) : void =
NoteTrigger.Enable()
Print("Rhythm sequence enabled — beats will now fire {BeatTrigger.GetMaxTriggerCount()} times")
# Fires every time a beat reaches the BeatTrigger.
OnBeat(Agent : ?agent) : void =
Remaining := BeatTrigger.GetTriggerCountRemaining()
Print("Beat! {Remaining} beats left in this bar")
if (Remaining = 0):
# We used all our beats — silence the music driver until next round.
NoteTrigger.Disable()
Line by line:
NoteTriggerandBeatTriggerare@editablefields, so after building you bind each to the real placed device in the Details panel. The= note_trigger_device{}/= trigger_device{}defaults are placeholders the editor overwrites.OnBeginruns once when the game loads. We immediatelyNoteTrigger.Disable()so music can't fire gameplay before the round starts.SetMaxTriggerCount(8)caps the beat trigger at 8 activations (the value is clamped to [0,20], where0means unlimited).SetResetDelay(2.0)forces a 2-second cooldown after the cap.SetTransmitDelay(0.0)means it tells linked devices immediately.BeatTrigger.TriggeredEvent.Subscribe(OnBeat)wires our method to the trigger's event.StartPlate.TriggeredEvent.Subscribe(OnStart)does the same for the start plate.- A
listenable(?agent)hands the handler(Agent : ?agent)— an optional agent. We don't need the agent here, so we accept it but don't unwrap it. - In
OnBeat,GetTriggerCountRemaining()returns how many beats are left. When it hits0, weDisable()the note trigger so the music stops driving gameplay.
Common patterns
1. Enable the note trigger only while a boss is alive. Use the note trigger's own Enable/Disable to gate when music drives traps.
boss_music_traps_device := class(creative_device):
@editable
NoteTrigger : note_trigger_device = note_trigger_device{}
# Player interacts to "summon" the boss and start music-driven traps.
@editable
SummonPad : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
NoteTrigger.Disable()
SummonPad.TriggeredEvent.Subscribe(OnSummon)
OnSummon(Agent : ?agent) : void =
# Boss appears: every musical note can now spring a trap.
NoteTrigger.Enable()
if (A := Agent?):
Print("Boss summoned — music traps live!")
2. Manually firing a trigger with a specific agent. The trigger_device has two Trigger overloads — one with no args, one taking an agent. Use the agent overload to attribute a music beat to a particular player.
beat_attribution_device := class(creative_device):
@editable
BeatTrigger : trigger_device = trigger_device{}
# The dancer's plate — last player to step here "owns" the beats.
@editable
DancePlate : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
DancePlate.TriggeredEvent.Subscribe(OnDance)
OnDance(Agent : ?agent) : void =
if (Dancer := Agent?):
# Re-fire the beat trigger crediting this specific dancer.
BeatTrigger.Trigger(Dancer)
else:
# No agent (e.g. fired by code) — fire the agent-less overload.
BeatTrigger.Trigger()
3. Reading and tuning rhythm timing at runtime. Adjust reset/transmit delay to change how 'fast' the beat gameplay feels.
tempo_tuner_device := class(creative_device):
@editable
BeatTrigger : trigger_device = trigger_device{}
# Stepping here doubles the tempo (halves the reset delay).
@editable
FastPad : trigger_device = trigger_device{}
OnBegin<override>()<suspends>:void =
BeatTrigger.SetResetDelay(1.0)
FastPad.TriggeredEvent.Subscribe(OnFast)
OnFast(Agent : ?agent) : void =
Current := BeatTrigger.GetResetDelay()
Faster := Current / 2.0
BeatTrigger.SetResetDelay(Faster)
Transmit := BeatTrigger.GetTransmitDelay()
Print("Reset delay now {Faster}s, transmit delay {Transmit}s")
Gotchas
- The
note_trigger_deviceonly exposesEnable/Disablein Verse. Its actual note-to-gameplay wiring is done in the editor's device-binding panel. You cannot read 'which note fired' in Verse — route the note trigger's output to a regulartrigger_device(or other device) and read that device's events. TriggeredEventhands you a?agent, not anagent. Always unwrap withif (A := Agent?):before using the player. Music/code triggers may sendfalse(no agent), so guard for it.SetMaxTriggerCountclamps to [0,20]. Passing25won't error but will be capped at20. Use0for unlimited.GetTriggerCountRemaining()returns0when the max is unlimited — not 'infinity'. Don't treat0as 'no beats left' unless you also know the max isn't0.- No int↔float auto-convert.
SetResetDelaytakes afloat(2.0),SetMaxTriggerCounttakes anint(8). Mixing them (SetResetDelay(2)) won't compile. @editabledevice fields must be bound in the Details panel after building Verse, or the calls hit an unconfigured placeholder and do nothing at runtime.message-typed params need a localized value, not a raw string — though none of this device's methods take one, remember this when wiring HUD messages alongside your rhythm logic.