Reference Devices compiles

vine_rail_device: Swinging Into Game Logic

The `vine_rail_device` is the jungle-themed cousin of the Grind Rail — it lets players swing and slide along a vine path you've placed in your island. Beyond the visual flair, its Verse API gives you two powerful events (`StartedGrindingEvent` and `EndedGrindingEvent`) plus `Enable`/`Disable` and `Hide`/`Show` methods, so you can build mechanics like timed vine challenges, secret shortcuts that only unlock after a puzzle, or score multipliers for players who ride the vine to the end.

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

Overview

The vine_rail_device creates a customizable vine version of the classic Grind Rail. Players can grab onto it and slide along its path, making it perfect for traversal puzzles, obstacle courses, jungle-themed maps, and momentum-based challenges.

When do you reach for it?

  • Timed vine challenges — start a countdown the moment a player grabs the vine, stop it when they dismount.
  • Gated shortcuts — keep the vine disabled until the player completes a prior objective, then call Enable() to open the route.
  • Hidden paths — call Hide() so the vine is invisible but still rideable, revealing it as a reward with Show().
  • Score or buff triggers — grant items or apply effects the instant a player starts or finishes a grind.

The device exposes:

  • StartedGrindingEvent — fires when a player first grabs the vine.
  • EndedGrindingEvent — fires when a player leaves the vine (dismount, fall off, or reach the end).
  • Enable() / Disable() — toggle whether the vine is rideable.
  • Hide() / Show() — toggle visibility (note: a hidden vine can still be ridden if enabled).

API Reference

vine_rail_device

Used to create a customizable vine version of the Grind Rails.

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

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

Events (subscribe a handler to react):

Event Signature Description
StartedGrindingEvent StartedGrindingEvent<public>:listenable(agent) Signaled when an agent starts grinding on this vine_rail_device.
EndedGrindingEvent EndedGrindingEvent<public>:listenable(agent) Signaled when an agent starts grinding on this vine_rail_device.

Methods (call these to make the device act):

Method Signature Description
Enable Enable<public>():void Enables this device, letting players grind on the vines.
Disable Disable<public>():void Disables this device, preventing players from grinding on the vines.
Hide Hide<public>():void Hides the track. Players can still grind on the track if it is enabled.
Show Show<public>():void Make this track visible.

Walkthrough

Scenario: A jungle obstacle course has a vine rail that is initially locked. When the player steps on a trigger plate, the vine becomes active and visible. The moment the player grabs the vine a countdown HUD message is implied (here we track the grind with Print stand-ins replaced by real device calls). When the player finishes the grind, the vine is hidden and disabled again — a one-shot secret shortcut.

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

# Localizer helper so we can pass messages to devices that require `message`
vine_unlock_manager_device := class(creative_device):

    # The vine rail placed in the level — wire this up in the UEFN Details panel
    @editable
    VineRail : vine_rail_device = vine_rail_device{}

    # A trigger plate the player must step on to unlock the vine
    @editable
    UnlockPlate : trigger_device = trigger_device{}

    # Called once at game start
    OnBegin<override>()<suspends> : void =
        # Start with the vine disabled and hidden — it's a secret shortcut
        VineRail.Disable()
        VineRail.Hide()

        # When the player steps on the unlock plate, open the vine
        UnlockPlate.TriggeredEvent.Subscribe(OnPlateTriggered)

        # React to the player grabbing the vine
        VineRail.StartedGrindingEvent.Subscribe(OnVineGrabbed)

        # React to the player finishing (or falling off) the vine
        VineRail.EndedGrindingEvent.Subscribe(OnVineReleased)

    # Handler: unlock plate stepped on
    OnPlateTriggered(Agent : ?agent) : void =
        # Reveal and enable the vine for one use
        VineRail.Show()
        VineRail.Enable()

    # Handler: player grabbed the vine
    # StartedGrindingEvent is listenable(agent), so the payload is a plain agent
    OnVineGrabbed(Grinder : agent) : void =
        # The vine is now in use — disable the unlock plate so no one else triggers it
        UnlockPlate.Disable()

    # Handler: player left the vine
    OnVineReleased(Grinder : agent) : void =
        # Hide and lock the vine again — one-shot shortcut is spent
        VineRail.Disable()
        VineRail.Hide()

Line-by-line breakdown:

Lines What's happening
@editable VineRail Declares the vine rail reference. You MUST wire this in the UEFN Details panel — bare identifiers won't work.
@editable UnlockPlate The trigger plate that gates access to the vine.
VineRail.Disable() / VineRail.Hide() Called in OnBegin so the vine starts locked and invisible.
UnlockPlate.TriggeredEvent.Subscribe(OnPlateTriggered) Subscribes to the plate; the handler signature matches listenable(?agent).
VineRail.StartedGrindingEvent.Subscribe(OnVineGrabbed) Subscribes to the vine grab event.
VineRail.EndedGrindingEvent.Subscribe(OnVineReleased) Subscribes to the vine release event.
OnVineGrabbed(Grinder : agent) StartedGrindingEvent is listenable(agent) — the payload is a plain agent, no option unwrap needed.
VineRail.Show() / VineRail.Enable() Reveals and activates the vine when the plate is stepped on.
VineRail.Disable() / VineRail.Hide() Locks the vine away again after the grind ends.

Common patterns

Pattern 1 — Score multiplier while riding the vine

Grant a player a score bonus every second they stay on the vine. Uses StartedGrindingEvent and EndedGrindingEvent together with a race to cancel the scoring loop the moment they dismount.

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

vine_score_multiplier_device := class(creative_device):

    @editable
    VineRail : vine_rail_device = vine_rail_device{}

    @editable
    ScoreManager : score_manager_device = score_manager_device{}

    OnBegin<override>()<suspends> : void =
        VineRail.StartedGrindingEvent.Subscribe(OnGrindStart)
        VineRail.EndedGrindingEvent.Subscribe(OnGrindEnd)

    # Tracks whether the grind is active so we can cancel the scoring loop
    var GrindActive : logic = false

    OnGrindStart(Grinder : agent) : void =
        set GrindActive = true
        # Kick off a concurrent scoring loop for this grinder
        spawn { ScoreLoop(Grinder) }

    OnGrindEnd(Grinder : agent) : void =
        set GrindActive = false

    # Awards points every second the player stays on the vine
    ScoreLoop(Grinder : agent)<suspends> : void =
        loop:
            if (not GrindActive?):
                break
            Sleep(1.0)
            if (GrindActive?):
                ScoreManager.Activate(Grinder)

Note: logic in Verse is the boolean type. not GrindActive? checks the falsy branch. spawn launches the async loop without blocking OnGrindStart.


Pattern 2 — Toggling vine visibility as a puzzle reveal

Uses Hide() and Show() independently of Enable/Disable — the vine stays rideable the whole time, but is invisible until the player solves a puzzle (here represented by a second trigger plate).

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

vine_reveal_puzzle_device := class(creative_device):

    @editable
    VineRail : vine_rail_device = vine_rail_device{}

    # Puzzle completion plate — wire to whatever objective you like
    @editable
    PuzzlePlate : trigger_device = trigger_device{}

    OnBegin<override>()<suspends> : void =
        # Vine is enabled (rideable) but invisible — a hidden path
        VineRail.Enable()
        VineRail.Hide()
        PuzzlePlate.TriggeredEvent.Subscribe(OnPuzzleSolved)

    OnPuzzleSolved(Agent : ?agent) : void =
        # Reveal the vine visually; it was already rideable
        VineRail.Show()
        # Disable the plate so the reveal only fires once
        PuzzlePlate.Disable()

Pattern 3 — Disabling the vine mid-game as a hazard

A game-manager device that disables a vine rail after a countdown, turning a safe traversal route into a trap. Demonstrates Disable() called from a timed async context.

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

vine_hazard_timer_device := class(creative_device):

    @editable
    VineRail : vine_rail_device = vine_rail_device{}

    # How many seconds before the vine is cut
    @editable
    CountdownSeconds : float = 30.0

    OnBegin<override>()<suspends> : void =
        VineRail.Enable()
        VineRail.Show()
        # Wait for the countdown, then cut the vine
        Sleep(CountdownSeconds)
        VineRail.Disable()
        VineRail.Hide()

Gotchas

1. @editable is mandatory — you cannot use a bare identifier

Every vine_rail_device you want to call methods on must be declared as an @editable field inside your class(creative_device) and wired in the UEFN Details panel. Writing vine_rail_device{}.Enable() compiles but does nothing — it creates a throwaway instance with no placed device behind it.

2. Event payload is agent, not ?agent

StartedGrindingEvent and EndedGrindingEvent are both listenable(agent) — the payload is a plain, non-optional agent. Your handler signature must be (Grinder : agent) : void, not (Grinder : ?agent) : void. Contrast this with trigger_device.TriggeredEvent which is listenable(?agent) and does require an option unwrap.

3. Hide() does NOT disable grinding

A hidden vine rail is still rideable if Enable() has been called. This is intentional and can be a powerful design tool (invisible vine paths), but it also means you must call both Hide() and Disable() if you want to fully remove the vine from play.

4. EndedGrindingEvent fires on ANY exit

The event fires whether the player reached the end of the vine, jumped off mid-grind, or was eliminated. If your logic depends on a successful full-grind completion, you'll need additional state tracking (e.g., a position check or a separate trigger at the vine's endpoint).

5. Async handlers need spawn

Event handler callbacks (subscribed via Subscribe) are synchronous — they cannot themselves be <suspends>. If you need to do async work in response to a grind event (like Sleep then award a bonus), launch a concurrent task with spawn { MyAsyncFunction(Grinder) } inside the handler.

6. message parameters require a localizer

If you pass text to any device that accepts a message type (e.g., a HUD message device), you cannot pass a raw string. Declare a localizer: MyText<localizes>(S:string):message = "{S}" and call MyText("Vine grabbed!"). There is no StringToMessage function in Verse.

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