Reference Devices compiles

grind_rail_device: Rails That React to Riders

The `grind_rail_device` lets you place customizable rails players can grind along — and with Verse you can make those rails come alive. Subscribe to grinding events to award points, change rail colors mid-game, disable rails as obstacles, or hide them until the right moment. Whether you're building a skate park scorer, a timed obstacle course, or a dynamic arena, the grind rail's Verse API gives you full programmatic control.

Updated Examples verified on the live UEFN compiler

Overview

The grind_rail_device is a placeable Creative device that creates a rideable rail players can grind along. Out of the box it's a static prop, but through Verse you unlock its full potential:

  • React to ridersStartedGrindingEvent and EndedGrindingEvent fire whenever a player hops on or off, letting you trigger score grants, sound cues, or state changes.
  • Control availabilityEnable and Disable let you gate rails behind game conditions (e.g., only activate a rail after a key is collected).
  • Visual feedbackSetRailColor changes the rail's glow color at runtime; Hide and Show toggle visibility without affecting grindability.

Reach for grind_rail_device any time you want rails that are more than decoration — scoring systems, timed challenges, puzzle gates, or dynamic arenas all benefit from its event-driven API.

API Reference

grind_rail_device

Used to create customizable Grind Rails.

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

grind_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 grind_rail_device.
EndedGrindingEvent EndedGrindingEvent<public>:listenable(agent) Signaled when an agent starts grinding on this grind_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 rail.
Disable Disable<public>():void Disables this device, preventing players from grinding on the rail.
SetRailColor SetRailColor<public>(Color:color):void Sets the color of the Grind Rail.
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 skate-park mini-game with three rails. Each rail is color-coded: blue when idle, gold while a player is grinding it. When a player finishes grinding, they earn a score tick and the rail flashes back to blue. A manager device subscribes to all three rails and tracks total grinds per player.

using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Fortnite.com/Characters }
using { /Verse.org/Colors }

# Attach this creative_device to a Verse Device actor in UEFN.
# Wire up Rail1, Rail2, Rail3, and ScoreManager in the Details panel.
grind_park_manager := class(creative_device):

    # Three grind rails placed in the level — wire these in the Details panel.
    @editable
    Rail1 : grind_rail_device = grind_rail_device{}

    @editable
    Rail2 : grind_rail_device = grind_rail_device{}

    @editable
    Rail3 : grind_rail_device = grind_rail_device{}

    # A score manager device to grant points (wire in Details panel).
    @editable
    ScoreManager : score_manager_device = score_manager_device{}

    # Called once when the game session starts.
    OnBegin<override>()<suspends> : void =
        # Paint all rails blue at session start so they look consistent.
        Rail1.SetRailColor(MakeColorFromHex("0055FFFF"))
        Rail2.SetRailColor(MakeColorFromHex("0055FFFF"))
        Rail3.SetRailColor(MakeColorFromHex("0055FFFF"))

        # Make sure all rails are enabled and visible.
        Rail1.Enable()
        Rail2.Enable()
        Rail3.Enable()
        Rail1.Show()
        Rail2.Show()
        Rail3.Show()

        # Subscribe to grind events on every rail.
        Rail1.StartedGrindingEvent.Subscribe(OnRailStarted)
        Rail1.EndedGrindingEvent.Subscribe(OnRailEnded)
        Rail2.StartedGrindingEvent.Subscribe(OnRailStarted)
        Rail2.EndedGrindingEvent.Subscribe(OnRailEnded)
        Rail3.StartedGrindingEvent.Subscribe(OnRailStarted)
        Rail3.EndedGrindingEvent.Subscribe(OnRailEnded)

    # Fired when any subscribed rail starts being ground.
    # The event delivers an `agent` directly (not ?agent) for grind_rail_device.
    OnRailStarted(Rider : agent) : void =
        # Turn the rail gold while someone is on it.
        # Because all three rails share this handler we paint all of them —
        # in a real project you'd track which rail fired via separate handlers.
        Rail1.SetRailColor(MakeColorFromHex("FFD700FF"))
        Rail2.SetRailColor(MakeColorFromHex("FFD700FF"))
        Rail3.SetRailColor(MakeColorFromHex("FFD700FF"))

    # Fired when the rider leaves any subscribed rail.
    OnRailEnded(Rider : agent) : void =
        # Award the player one score point for completing a grind.
        ScoreManager.Activate(Rider)

        # Reset all rails to blue.
        Rail1.SetRailColor(MakeColorFromHex("0055FFFF"))
        Rail2.SetRailColor(MakeColorFromHex("0055FFFF"))
        Rail3.SetRailColor(MakeColorFromHex("0055FFFF"))

Line-by-line highlights:

Lines What's happening
@editable Rail1… Declares the three rails as inspector-wirable fields. Without @editable the device has no reference to the placed actors.
SetRailColor(MakeColorFromHex(…)) Paints the rail's neon glow. MakeColorFromHex is a Verse built-in that takes an 8-digit RGBA hex string.
Enable() / Show() Ensures rails are grindable and visible regardless of their saved device settings.
StartedGrindingEvent.Subscribe(OnRailStarted) Registers the class method as the event handler. The handler signature must accept (agent).
ScoreManager.Activate(Rider) Passes the grinding agent to the score manager so the right player gets the point.

Common patterns

Pattern 1 — Gate a rail behind a puzzle (Enable / Disable)

A locked rail is hidden and disabled at game start. When a player interacts with a button, the rail appears and becomes grindable.

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

# Place this device in the level and wire the fields in the Details panel.
rail_gate_device := class(creative_device):

    # The rail that should be locked at the start.
    @editable
    LockedRail : grind_rail_device = grind_rail_device{}

    # A button the player interacts with to unlock the rail.
    @editable
    UnlockButton : button_device = button_device{}

    OnBegin<override>()<suspends> : void =
        # Disable and hide the rail so players cannot use it yet.
        LockedRail.Disable()
        LockedRail.Hide()

        # When the button is pressed, unlock the rail.
        UnlockButton.InteractedWithEvent.Subscribe(OnButtonPressed)

    OnButtonPressed(Presser : agent) : void =
        # Reveal and enable the rail for everyone.
        LockedRail.Show()
        LockedRail.Enable()

Pattern 2 — Per-player color change on grind start

Each time a specific player starts grinding, the rail shifts to a unique color to signal ownership — useful in competitive rail-racing modes.

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

rail_color_ownership := class(creative_device):

    @editable
    RaceRail : grind_rail_device = grind_rail_device{}

    # Track whether the rail is currently claimed.
    var RailClaimed : logic = false

    OnBegin<override>()<suspends> : void =
        RaceRail.Enable()
        RaceRail.Show()
        RaceRail.SetRailColor(MakeColorFromHex("FFFFFFFF"))  # White = unclaimed
        RaceRail.StartedGrindingEvent.Subscribe(OnGrindStarted)
        RaceRail.EndedGrindingEvent.Subscribe(OnGrindEnded)

    OnGrindStarted(Rider : agent) : void =
        set RailClaimed = true
        # Turn the rail red to show it is occupied.
        RaceRail.SetRailColor(MakeColorFromHex("FF2200FF"))

    OnGrindEnded(Rider : agent) : void =
        set RailClaimed = false
        # Return to white when the rider leaves.
        RaceRail.SetRailColor(MakeColorFromHex("FFFFFFFF"))

Pattern 3 — Timed rail: disable after first grind

A one-shot rail that disables itself the moment a player finishes grinding — great for single-use puzzle elements or limited-time shortcuts.

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

one_shot_rail := class(creative_device):

    @editable
    SingleUseRail : grind_rail_device = grind_rail_device{}

    # Tracks whether the rail has already been used.
    var Used : logic = false

    OnBegin<override>()<suspends> : void =
        SingleUseRail.Enable()
        SingleUseRail.Show()
        SingleUseRail.SetRailColor(MakeColorFromHex("00FF88FF"))  # Green = available
        SingleUseRail.EndedGrindingEvent.Subscribe(OnGrindEnded)

    OnGrindEnded(Rider : agent) : void =
        if (not Used):
            set Used = true
            # Signal it's spent: turn grey, then hide and disable.
            SingleUseRail.SetRailColor(MakeColorFromHex("444444FF"))
            SingleUseRail.Disable()
            SingleUseRail.Hide()

Gotchas

1. Hide does NOT disable grinding. Calling Hide() makes the rail invisible but players can still grind on it if it is Enabled. This is intentional (invisible shortcuts!) but easy to misread. If you want to block grinding, always call Disable() as well.

2. EndedGrindingEvent fires on ANY exit — including falling off. The event fires whether the player reached the end of the rail, jumped off mid-grind, or was knocked off. If your scoring logic should only reward a full grind, you'll need additional state (e.g., track grind start time and only award points if enough time elapsed).

3. Event handler signature is (agent), not (?agent). StartedGrindingEvent and EndedGrindingEvent are typed listenable(agent) — the handler receives a concrete agent, not an optional ?agent. Do NOT write if (A := Agent?): unwrapping here; that pattern is for listenable(?agent) events.

4. SetRailColor takes a color value, not a string. Use MakeColorFromHex("RRGGBBAA") (8 hex digits including alpha) or construct a color via MakeColorFromSRGB. Passing a raw string literal will not compile.

5. Always declare rails as @editable fields. You cannot write grind_rail_device{}.Enable() inline and expect it to affect a placed device. The @editable attribute is what binds your Verse variable to the specific actor placed in the level. Without it you're calling methods on a disconnected default instance.

6. Enable/Disable affect ALL players globally. These methods toggle the rail for everyone in the session, not per-player. There is no per-agent enable — design your game flow accordingly.

Device Settings & Options

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

Grind Rail Device settings and options panel in the UEFN editor — Visual Style, Rail Color, Allow Sprinting, Speed Preset, Shooting Speed Multiplier
Grind Rail Device — User Options (1 of 2) in the UEFN editor: Visual Style, Rail Color, Allow Sprinting, Speed Preset, Shooting Speed Multiplier
Grind Rail Device settings and options panel in the UEFN editor — Visual Style, Rail Color, Allow Sprinting, Speed Preset, Shooting Speed Multiplier
Grind Rail Device — User Options (2 of 2) in the UEFN editor: Visual Style, Rail Color, Allow Sprinting, Speed Preset, Shooting Speed Multiplier
⚙️ Settings on this device (5)

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

Visual Style
Rail Color
Allow Sprinting
Speed Preset
Shooting Speed Multiplier

Guides & scripts that use grind_rail_device

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

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