Overview
Verse naming conventions are a set of agreed-upon rules for how you name classes, variables, functions, files, and modules. The Verse language itself does not enforce most of these rules at compile time — your code will compile whether you write mydevice or MyDevice — but the conventions exist because:
- The entire Fortnite/UEFN standard library uses them, so matching them makes your code read like a first-party API.
- UEFN's content browser surfaces class names directly; a well-named class like
vault_door_controlleris immediately discoverable. - Large islands with many Verse files become unmanageable without a consistent file-naming scheme.
When you reach for naming conventions you are solving a communication problem: how do you make the intent of every identifier obvious at a glance?
API Reference
(API surface could not be resolved for this device.)
Walkthrough
The scenario: a Vault Door puzzle room. A pressure plate unlocks the door, a countdown timer closes it again, and a score-granter rewards the player who made it through. We will build the Verse device that wires this together — and every identifier will follow Verse conventions so the code is immediately readable.
Naming rules in practice
| Construct | Convention | Example |
|---|---|---|
| Class name | snake_case |
vault_door_controller |
@editable device field |
PascalCase |
PressurePlate |
| Local variable | PascalCase |
TriggeringAgent |
| Method / function | PascalCase |
OnPlateTriggered |
| Module-level constant | PascalCase (all-caps words OK) |
MaxOpenSeconds |
var mutable field |
PascalCase |
IsOpen |
| File name | snake_case with role suffix |
vault_door_controller.verse |
<localizes> helper |
PascalCase |
VaultMessage |
Key insight: Classes and file names use
snake_case; almost everything else (fields, variables, functions) usesPascalCase. This mirrors how Epic's own APIs look —creative_deviceis the class,OnBeginis the method.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/SpatialMath }
# File: vault_door_controller.verse
# Naming conventions demonstrated:
# - Class: snake_case (vault_door_controller)
# - @editable fields: PascalCase (PressurePlate, DoorDevice, etc.)
# - Methods: PascalCase (OnPlateTriggered, CloseDoor)
# - Local vars: PascalCase (TriggeringAgent, OpenPosition)
# - Constants: PascalCase (DoorOpenDurationSeconds)
# - <localizes>: PascalCase (VaultOpenMessage)
# Module-level localized message helper — PascalCase function name
VaultOpenMessage<localizes>(S : string) : message = "{S}"
# Class name: snake_case, as all Verse class names are
vault_door_controller := class(creative_device):
# @editable fields are PascalCase — they appear in the UEFN
# details panel exactly as written, so clear names matter.
@editable
PressurePlate : trigger_device = trigger_device{}
@editable
DoorDevice : creative_device = creative_device{}
# A module-level constant expressed as a field — PascalCase
DoorOpenDurationSeconds : float = 5.0
# Mutable state field — PascalCase var
var IsOpen : logic = false
# OnBegin: override from creative_device (PascalCase, matches Epic's API)
OnBegin<override>()<suspends> : void =
# Subscribe uses a PascalCase method name for the handler
PressurePlate.TriggeredEvent.Subscribe(OnPlateTriggered)
# Event handler — PascalCase, verb phrase describing what happened
OnPlateTriggered(TriggeringAgent : ?agent) : void =
# `logic` is fallible, so query it with `?` and use `else:` for the false case
if (IsOpen?):
# Already open, do nothing
else:
set IsOpen = true
# Show the door device (it was hidden, acting as a closed vault)
# Then spawn a timed close coroutine
spawn { CloseDoorAfterDelay() }
# Private helper — PascalCase verb phrase
CloseDoorAfterDelay()<suspends> : void =
# Wait for the configured duration
Sleep(DoorOpenDurationSeconds)
set IsOpen = false```
### Line-by-line explanation
**`VaultOpenMessage<localizes>`** — A module-level function whose name is `PascalCase`. The `<localizes>` specifier turns it into a `message` producer. Naming it with a noun phrase (`VaultOpenMessage`) makes its purpose obvious.
**`vault_door_controller`** — The class name is `snake_case`, matching every class in the Verse standard library (`creative_device`, `trigger_device`, `barrier_device`). UEFN's content browser will show this exact string.
**`PressurePlate`, `DoorDevice`** — `@editable` fields are `PascalCase`. Because UEFN surfaces these in the Details panel, a name like `PressurePlate` is self-documenting to a designer who has never read the code.
**`DoorOpenDurationSeconds`** — A constant field. The name encodes both the concept (`DoorOpenDuration`) and the unit (`Seconds`), a best practice when dealing with numeric values.
**`var IsOpen : logic`** — Mutable state is still `PascalCase`. The `var` keyword signals mutability; the name signals boolean state with a simple adjective phrase.
**`OnPlateTriggered`** — Event handler names conventionally start with `On` followed by a past-tense description of what happened. This mirrors Epic's own events (`OnBegin`, `OnEnd`).
**`TriggeringAgent`** — Local variable, `PascalCase`. The name answers *what is this?* without a comment.
**`CloseDoorAfterDelay`** — A helper method. Verb phrase, `PascalCase`, describes the action and the timing.
## Common patterns
### Pattern 1 — File and module organization with snake_case names
Large islands split logic across multiple files. The convention is `[system]_[role].verse`. Each file holds one focused class or set of helpers.
```verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# File: score_config.verse
# Role suffix "_config" signals this file holds tunable constants.
# The class name follows snake_case.
score_config := class(creative_device):
# PascalCase constants — units in the name prevent bugs
PointsPerElimination : int = 100
PointsPerObjective : int = 250
BonusMultiplier : float = 1.5
# OnBegin does nothing here; this device is a data container.
OnBegin<override>()<suspends> : void =
# Config devices typically just hold values other devices read.
Sleep(0.0)
Pattern 2 — PascalCase event handlers with clear verb phrases
Subscribing to multiple events in one device is common. Consistent On[Event] naming makes the subscription list read like a table of contents.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# File: arena_round_controller.verse
arena_round_controller := class(creative_device):
@editable
RoundStartButton : button_device = button_device{}
@editable
RoundEndTrigger : trigger_device = trigger_device{}
# Mutable round counter — PascalCase var
var CurrentRound : int = 0
OnBegin<override>()<suspends> : void =
# Each subscription line reads like a sentence:
# "When the button is interacted with, call OnRoundStarted."
RoundStartButton.InteractedWithEvent.Subscribe(OnRoundStarted)
RoundEndTrigger.TriggeredEvent.Subscribe(OnRoundEnded)
# Handler name: On + past-tense event description
OnRoundStarted(InstigatingAgent : ?agent) : void =
set CurrentRound += 1
# Handler name follows the same On + past-tense pattern
OnRoundEnded(InstigatingAgent : ?agent) : void =
# Round cleanup logic would go here
set CurrentRound = 0
Pattern 3 — Localized message helpers with PascalCase names
Whenever you display text to players you need a <localizes> function. Name it with a noun phrase that describes the message category.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
# File: hud_message_controller.verse
# Module-level <localizes> helpers — PascalCase noun phrases
ObjectiveCompleteMessage<localizes>(ObjectiveName : string) : message = "Objective Complete: {ObjectiveName}"
TimerExpiredMessage<localizes>() : message = "Time's Up!"
WelcomeMessage<localizes>(PlayerName : string) : message = "Welcome, {PlayerName}!"
hud_message_controller := class(creative_device):
@editable
HUDMessageDevice : hud_message_device = hud_message_device{}
@editable
ObjectiveTrigger : trigger_device = trigger_device{}
OnBegin<override>()<suspends> : void =
ObjectiveTrigger.TriggeredEvent.Subscribe(OnObjectiveTriggered)
OnObjectiveTriggered(TriggeringAgent : ?agent) : void =
# Pass a localized message — NOT a raw string
# The helper name ObjectiveCompleteMessage clearly signals its purpose
HUDMessageDevice.SetText(ObjectiveCompleteMessage("Vault Opened"))
if (A := TriggeringAgent?):
HUDMessageDevice.Show(A)
Gotchas
1. Classes are snake_case, everything else is PascalCase — don't mix them up
The single most common mistake is writing a class in PascalCase (VaultDoorController) or a field in snake_case (pressure_plate). While the compiler accepts both, your code will look alien next to Epic's APIs. Adopt the rule immediately: if it's a class or file name, use snake_case; if it's anything else, use PascalCase.
2. @editable field names appear verbatim in the UEFN Details panel
When a designer opens your device in UEFN, they see your @editable field names exactly as written. Pd or trig1 tells them nothing. PressurePlate or RoundEndTrigger is self-documenting. Treat every @editable name as public API.
3. File names should encode both system and role
A file called controller.verse is useless when you have ten of them. The convention [system]_[role].verse — e.g., vault_door_controller.verse, score_config.verse, player_data.verse — makes the content browser and file tree scannable at a glance. The roles are: _controller (creative_device), _config (constants/tunables), _data (state structures), _module (shared helpers).
4. Localized text helpers must be PascalCase functions, not raw strings
You cannot pass a raw string where a message is expected. You must declare a <localizes> function. Name it clearly — TimerExpiredMessage is better than Msg2 — because these helpers accumulate quickly in a large project and you will need to find them by name.
5. Unit suffixes prevent numeric bugs
Verse does not have a unit type system. A field named Duration could be seconds, milliseconds, or frames. A field named DurationSeconds is unambiguous. Apply this to any numeric field where the unit is not obvious from context: SpeedCentimetersPerSecond, DamagePoints, CooldownSeconds.
6. var signals mutability — use it sparingly and name accordingly
Mutable state (var) is the source of most concurrency bugs. When you do need it, name the field so its mutability is obvious from context: IsOpen, CurrentRound, RemainingLives. Avoid vague names like State or Flag for mutable fields — the name should tell you what changes and why.