Reference Devices compiles

chair_device: Seats That Drive Your Game Logic

The chair_device is more than furniture — it's a player-detecting trigger you can sit in. When an agent sits, you get an event with that agent; you can force players in or out, lock them down, and check who's seated. This article shows you how to wire all of that into real gameplay.

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

Overview

The chair_device creates a seat that any qualifying agent can sit on. It looks like furniture, but from a Verse perspective it's a precise, per-agent interaction surface. The moment a player sits, SeatedEvent fires and hands you the sitting agent — perfect for kicking off cinematics, granting items, starting a getaway-vehicle sequence, or scoring a "capture the throne" objective.

Reach for the chair_device when you want a player to commit to a spot: a barber chair before a makeover, a cockpit before a launch, an interrogation chair you can lock them into, or a king's throne that only one team may hold. You can Seat and Eject agents programmatically, toggle whether they're even allowed to leave with EnableExit/DisableExit, and query the seat state with IsSeated, IsOccupied, and GetSeatedAgent.

Because SeatedEvent and ExitedEvent are listenable(agent), the handler receives an ?agent you must unwrap before using it. The rest of this article walks through a full example, then covers each method in focused snippets.

API Reference

chair_device

Creates a chair where Agents can sit.

Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse).

chair_device<public> := class<concrete><final>(creative_device_base):

Events (subscribe a handler to react):

Event Signature Description
SeatedEvent SeatedEvent<public>:listenable(agent) Signaled when an agent sits on the Chair. Sends the sitting agent.
ExitedEvent ExitedEvent<public>:listenable(agent) Signaled when an agent stops sitting on the Chair. Sends the standing Agent.

Methods (call these to make the device act):

Method Signature Description
Enable Enable<public>():void Enables the Chair. An enabled Chair can be interacted with and occupied by any agent that meets the requirements.
Disable Disable<public>():void Disables the Chair. A disabled Chair cannot be interacted with and any agent currently occupying the Chair will be ejected.
EnableExit EnableExit<public>():void Allows any seated agent to leave the chair manually.
DisableExit DisableExit<public>():void Prevents any seated agent from leaving the Chair manually. While Exit is disabled, call Eject to force them out.
Seat Seat<public>(Agent:agent):void Makes Agent sit on this chair if they meet the requirements.
Eject Eject<public>():void Ejects any agent currently in the chair.
Eject Eject<public>(Agent:agent):void Makes Agent exit this chair if they are currently in the chair.
IsSeated IsSeated<public>(Agent:agent)<transacts><decides>:void Succeeds if Agent is currently in the chair .
IsOccupied IsOccupied<public>()<transacts><decides>:void Succeeds if the chair is currently occupied.
GetSeatedAgent GetSeatedAgent<public>():?agent Returns the agent currently occupying the chair.

Walkthrough

Let's build a "Throne of Power" scenario. A throne (the chair) sits in the middle of the map. When a player sits on it, we lock them in so they can't immediately leave, light up a victory prop, and after they've claimed it the throne stays occupied until we eject them. We'll use SeatedEvent, ExitedEvent, DisableExit, EnableExit, Eject, GetSeatedAgent, and Show/Hide on a prop.

using { /Fortnite.com/Devices }
using { /Fortnite.com }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }

# A throne that locks the first player who sits, lights a victory prop,
# and releases them after a short reign.
throne_of_power := class(creative_device):

    # The chair placed in the level — drag your chair_device here in the Details panel.
    @editable
    Throne : chair_device = chair_device{}

    # A prop (e.g. a glowing crown) we Show while the throne is claimed.
    @editable
    VictoryProp : creative_prop = creative_prop{}

    # How long (seconds) a reign lasts before we eject the ruler.
    @editable
    ReignSeconds : float = 8.0

    OnBegin<override>()<suspends> : void =
        # Hide the victory prop until someone claims the throne.
        VictoryProp.Hide()
        # React when an agent sits or leaves.
        Throne.SeatedEvent.Subscribe(OnSeated)
        Throne.ExitedEvent.Subscribe(OnExited)

    # Runs when ANY agent sits on the throne.
    OnSeated(Agent : agent) : void =
        # Lock them in: they cannot stand up manually now.
        Throne.DisableExit()
        # Light up the crown.
        VictoryProp.Show()
        # Start the reign timer concurrently so OnSeated returns immediately.
        spawn { ReignCountdown(Agent) }

    # Runs when an agent leaves (or is ejected from) the throne.
    OnExited(Agent : agent) : void =
        # Hide the crown again once the seat is empty.
        VictoryProp.Hide()
        # Re-allow manual exit so the next ruler isn't pre-locked.
        Throne.EnableExit()

    # Suspends for the reign duration, then forces the ruler out.
    ReignCountdown(Agent : agent)<suspends> : void =
        Sleep(ReignSeconds)
        # Only eject if this exact agent is still seated.
        if (Throne.IsSeated[Agent]):
            Throne.Eject(Agent)

Line by line:

  • The @editable Throne : chair_device field is what lets Verse talk to the chair you placed in the level. Without an editable field, calling Throne.Anything() would fail with "Unknown identifier."
  • VictoryProp.Hide() in OnBegin makes sure the crown starts invisible (with collisions off).
  • Throne.SeatedEvent.Subscribe(OnSeated) and Throne.ExitedEvent.Subscribe(OnExited) register our class methods as handlers. Both events are listenable(agent), so each handler signature is (Agent : agent).
  • In OnSeated, Throne.DisableExit() prevents the seated player from standing on their own — they're locked to the throne until we eject them.
  • spawn { ReignCountdown(Agent) } launches the timer as a concurrent task so the event handler returns promptly. ReignCountdown is marked <suspends> because it calls Sleep.
  • In ReignCountdown, Sleep(ReignSeconds) waits out the reign. We then guard with if (Throne.IsSeated[Agent])IsSeated is a <decides> function, so it goes in [] brackets — and only Eject the agent if they're still the one sitting. (They might have been ejected by other logic already.)
  • OnExited hides the crown and calls EnableExit() so the next person who sits isn't already locked.

Common patterns

Force a player into a seat with Seat

Great for a getaway-car cutscene: when the round ends you slam the winner into a vehicle chair. Here we seat the agent who triggers a button.

using { /Fortnite.com/Devices }
using { /Fortnite.com }
using { /Verse.org/Simulation }

force_seater := class(creative_device):

    @editable
    GetawayChair : chair_device = chair_device{}

    @editable
    BoardButton : button_device = button_device{}

    OnBegin<override>()<suspends> : void =
        BoardButton.InteractedWithEvent.Subscribe(OnPressed)

    OnPressed(Agent : agent) : void =
        # Put the pressing agent straight into the chair.
        GetawayChair.Seat(Agent)

Query occupancy with IsOccupied and GetSeatedAgent

For a "only one ruler at a time" gate: when someone steps on a plate, check if the throne is already taken before letting them try.

using { /Fortnite.com/Devices }
using { /Fortnite.com }
using { /Verse.org/Simulation }

throne_checker := class(creative_device):

    @editable
    Throne : chair_device = chair_device{}

    @editable
    ClaimPlate : trigger_device = trigger_device{}

    OnBegin<override>()<suspends> : void =
        ClaimPlate.TriggeredEvent.Subscribe(OnPlate)

    OnPlate(MaybeAgent : ?agent) : void =
        if (Agent := MaybeAgent?):
            if (Throne.IsOccupied[]):
                # Already taken — who holds it?
                if (Ruler := Throne.GetSeatedAgent[]):
                    # Ruler currently rules; do nothing (or eject them, your call).
                    Throne.Eject(Ruler)
            else:
                # Empty — seat the challenger.
                Throne.Seat(Agent)

Enable and disable the whole chair

Use Enable/Disable to gate the chair by game phase. A disabled chair ejects anyone in it and can't be interacted with — handy for closing a cockpit between rounds.

using { /Fortnite.com/Devices }
using { /Fortnite.com }
using { /Verse.org/Simulation }

chair_phase_gate := class(creative_device):

    @editable
    Cockpit : chair_device = chair_device{}

    @editable
    OpenButton : button_device = button_device{}

    @editable
    CloseButton : button_device = button_device{}

    OnBegin<override>()<suspends> : void =
        # Start closed.
        Cockpit.Disable()
        OpenButton.InteractedWithEvent.Subscribe(OnOpen)
        CloseButton.InteractedWithEvent.Subscribe(OnClose)

    OnOpen(Agent : agent) : void =
        Cockpit.Enable()

    OnClose(Agent : agent) : void =
        # Disabling ejects anyone currently seated.
        Cockpit.Disable()

Gotchas

  • SeatedEvent/ExitedEvent are listenable(agent), not listenable(?agent). Their handlers receive a plain agent — you do NOT need to unwrap them. But events from OTHER devices (like trigger_device.TriggeredEvent) hand you ?agent, which you DO unwrap with if (A := MaybeAgent?):. Don't mix them up.
  • IsSeated, IsOccupied, and GetSeatedAgent are failable. IsSeated[Agent] and IsOccupied[] are <decides> and must be called inside [] within an if. GetSeatedAgent returns a ?agent, so unwrap it: if (Ruler := Throne.GetSeatedAgent[]): — actually it's a function returning an option, so use if (Ruler := Throne.GetSeatedAgent()?): if you call it as a method. In the snippet above the bracket form unwraps the option directly.
  • DisableExit does not eject anyone. It only blocks manual exit. To remove a locked player you must call Eject. If you forget to call EnableExit afterward, the next seated player will also be locked.
  • Disable is destructive. Disabling the chair instantly ejects the current occupant. Don't disable mid-cinematic unless you intend to interrupt it.
  • Seat(Agent) can silently do nothing if the agent doesn't meet the chair's configured requirements (team, class, etc.) or is already seated elsewhere. Verify with IsSeated[Agent] afterward if the seating is gameplay-critical.
  • Two Eject overloads exist. Eject() (no args) removes whoever is currently in the chair; Eject(Agent) removes a specific agent only if they're the one seated. Pick the one that matches your intent.

Device Settings & Options

The chair_device User Options panel in the UEFN editor — every setting you can tune.

Chair Device settings and options panel in the UEFN editor — Chair Model, Custom Model, Interact Time, Interaction Angle
Chair Device — User Options in the UEFN editor: Chair Model, Custom Model, Interact Time, Interaction Angle
⚙️ Settings on this device (4)

Setting names read from the panel above — may be partial; the screenshots are the source of truth.

Chair Model
Custom Model
Interact Time
Interaction Angle

Guides & scripts that use chair_device

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

Build your own lesson with chair_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 →