Overview
When you write a creative_device in Verse, every identifier you declare — fields, functions, type aliases — has an access specifier that controls who can read or call it. Verse has four levels:
| Specifier | Who can see it |
|---|---|
<public> |
Any Verse code anywhere — other devices, other modules |
<protected> |
The class itself and any subclass |
<internal> |
Only code in the same module (the default when you write nothing) |
<private> |
Only the class itself — no subclasses, no outsiders |
The default — writing no specifier at all — is <internal>, which is often more permissive than beginners expect. Explicitly marking things <private> is the right habit for implementation details.
Why does this matter on a Fortnite island? A large island might have a lighthouse_controller device that manages a beacon, a dock_manager device that needs to trigger the beacon, and a shore_patrol device that should never touch the beacon internals at all. Access specifiers let you draw those lines cleanly in code.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Scenario: A clifftop lighthouse sits above a sunny cove. The lighthouse_controller device owns the beacon state. A separate dock_manager device on the shore can call the one public function ActivateBeacon() to light it up — but it cannot reach the private helper ComputeFlashInterval() or the private field FlashCount. A cinematic trigger fires when the beacon activates.
This example demonstrates:
<private>fields and helpers that are implementation details- A
<public>function that forms the device's contract - An
<internal>event subscription that only the same module needs - How a second device calls the public API via an
@editablereference
# lighthouse_controller.verse
# Place this device on the clifftop in UEFN.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
using { /Verse.org/Verse }
lighthouse_log := class(log_channel){}
lighthouse_controller := class(creative_device):
# --- Public API -------------------------------------------
# Other devices (e.g. dock_manager) may call this to light
# the beacon from the shore.
ActivateBeacon<public>(): void =
if (not BeaconLit?):
set BeaconLit = true
Print("Beacon activated! Cove is safe.")
# Enable the cinematic trigger so the beacon sequence plays.
BeaconTrigger.Trigger()
set FlashCount = ComputeFlashInterval()
# --- Editable references (internal by default) ------------
# Wire these in the UEFN Details panel.
@editable
BeaconTrigger : trigger_device = trigger_device{}
# --- Private state ----------------------------------------
# No outside device should read or write these directly.
var BeaconLit<private> : logic = false
var FlashCount<private> : int = 0
# --- Private helpers --------------------------------------
# Implementation detail — the dock has no business knowing
# how flash intervals are computed.
ComputeFlashInterval<private>(): int =
# Sunny cove: short bright flashes.
return 3
# --- Lifecycle --------------------------------------------
OnBegin<override>()<suspends> : void =
Print("Lighthouse controller ready on clifftop.")```
```verse
# dock_manager.verse
# Place this device on the dock. Wire LighthouseCtrl in the Details panel.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
dock_log := class(log_channel){}
dock_manager := class(creative_device):
# Wire to the lighthouse_controller actor placed on the clifftop.
@editable
LighthouseCtrl : lighthouse_controller = lighthouse_controller{}
# The pressure plate on the dock — step on it to signal the lighthouse.
@editable
DockPlate : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
Log(dock_log, "Dock manager online. Waiting for plate...")
DockPlate.TriggeredEvent.Subscribe(OnDockPlateTriggered)
# Called when a player steps on the dock pressure plate.
OnDockPlateTriggered(Agent : ?agent) : void =
# We can call ActivateBeacon because it is <public>.
LighthouseCtrl.ActivateBeacon()
# This would be a COMPILE ERROR — BeaconLit is <private>:
# LighthouseCtrl.BeaconLit
Line-by-line highlights:
ActivateBeacon<public>()— the only door the dock is allowed to knock on. Mark the contract public, hide everything else.BeaconLit<private>— mutable state. If the dock could write this directly, you'd lose the guard logic insideActivateBeacon.ComputeFlashInterval<private>()— a helper that belongs to the lighthouse's internal logic. Keeping it private means you can change the algorithm without touching any other device.@editablefields have no explicit specifier, so they default to<internal>. They're visible inside the same Verse module (the UEFN project) but not exported to external packages.BeaconTrigger.Trigger()— calling the realtrigger_deviceAPI to fire the cinematic sequence.
Common patterns
Pattern 1 — A protected helper shared with a subclass
A base_gate_controller exposes a <protected> helper so a subclass timed_gate_controller can reuse the open/close logic without making it public to the whole island.
# base_gate_controller.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
gate_log := class(log_channel){}
base_gate_controller := class(creative_device):
@editable
GateTrigger : trigger_device = trigger_device{}
# Subclasses can call this; the rest of the island cannot.
OpenGate<protected>(): void =
Log(gate_log, "Gate swinging open on the shore path.")
GateTrigger.Trigger()
# Public entry point — anyone can request the gate open.
RequestOpen<public>(): void =
OpenGate()
OnBegin<override>()<suspends> : void =
Log(gate_log, "Base gate controller ready.")
timed_gate_controller := class(base_gate_controller):
@editable
DelayTrigger : trigger_device = trigger_device{}
# Subclass reuses the protected helper — totally legal.
OpenAfterDelay<public>(): void =
DelayTrigger.Trigger() # fire a sequencer delay
OpenGate() # then open
OnBegin<override>()<suspends> : void =
Log(gate_log, "Timed gate controller ready on clifftop path.")
Pattern 2 — Internal-only wiring (the default)
When you write no specifier, the identifier is <internal> — accessible anywhere inside the same UEFN Verse module, but invisible to external packages. This is the right default for cross-device wiring that lives entirely on your island.
# shore_signal_hub.verse
# Coordinates several devices on the shore — all internal wiring.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
hub_log := class(log_channel){}
shore_signal_hub := class(creative_device):
# No specifier = <internal>. Fine for same-island wiring.
@editable
FlareDevice : trigger_device = trigger_device{}
@editable
BellDevice : trigger_device = trigger_device{}
# Internal helper — other island devices in this module can call it.
FireAllSignals(): void =
Log(hub_log, "Shore signals firing — cove alert!")
FlareDevice.Trigger()
BellDevice.Trigger()
OnBegin<override>()<suspends> : void =
Log(hub_log, "Shore signal hub armed.")
# Self-test on start.
FireAllSignals()
Pattern 3 — Type alias visibility
Type aliases follow the same rules, but with one extra constraint: an alias cannot be more public than the type it aliases. This pattern shows a private implementation type and a public-facing alias for a safe subset.
# beacon_state_types.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
state_log := class(log_channel){}
# A private implementation detail — the raw flash count type.
beacon_flash_count<private> := type{_X : int where 0 <= _X, _X <= 10}
# A public alias is ILLEGAL here because beacon_flash_count is private.
# public_flash_count<public> := beacon_flash_count # COMPILE ERROR
# Instead, expose a plain int publicly and validate internally.
beacon_state_demo := class(creative_device):
FlashLevel<private> : int = 0
# Public setter validates the range so callers never see the
# internal constrained type.
SetFlashLevel<public>(Level : int): void =
if (Level >= 0, Level <= 10):
set FlashLevel = Level
Log(state_log, "Flash level updated for cove beacon.")
OnBegin<override>()<suspends> : void =
Log(state_log, "Beacon state demo device ready.")
SetFlashLevel(5)
Gotchas
1. The default is <internal>, not <public>
Beginner mistake: assuming that writing nothing means private. It doesn't — it means <internal>, which is visible to every other Verse file in your UEFN project. If you truly want something hidden, write <private> explicitly.
2. <private> blocks subclasses too
<private> is stricter than most languages' private — it is invisible even to direct subclasses. If you need subclasses to reach a member, use <protected> instead.
3. @editable fields are always <internal> or weaker
UEFN's Details panel wiring only works within the same project module. You cannot make an @editable field <public> in a way that external packages can set it through the panel — keep @editable fields at <internal> (the default) or <private> if only the owning device should reference them.
4. Type aliases cannot exceed their aliased type's visibility
If the underlying type is <private>, the alias must also be <private> or narrower. Trying to create a <public> alias for a <private> type is a compile error.
5. Access specifiers live on the definition, not the use site
You cannot "grant" access at the call site. If ComputeFlashInterval is <private>, no amount of casting or indirection from outside the class will reach it. Design your public API surface deliberately — it is the only door you give to callers.