Overview
In Verse there is no separate "create a module" button. A folder in your project IS a module, and its name is the folder's name. Every .verse file inside that folder belongs to the same module and shares its namespace — so score_helpers.verse and game_manager.verse in the same Core/ folder can reference each other's definitions directly. Files in other folders reach in with a using directive that spells out the folder path.
Why reach for this? Picture a sunny clifftop cove map: players sprint down the dock, hit a checkpoint, and earn points. The scoring math, the localized banner text, and the win condition all want to be shared between several devices. Instead of pasting the same helper into every device file, you drop it in a folder — a module — and import it once. Your code stays DRY, and the compiler resolves every reference to exactly the right definition because module paths are unique and permanent.
This article uses two real placed devices to show modules in action: the score_manager_device (grants and increments points) and the player_reference_device (tracks which agent is the current leader). The organizing is done by folders; the doing is done by these devices' real API.
API Reference
(API surface could not be resolved for this device.)
Walkthrough
Our project folder looks like this:
CoveRace/
├── Core/
│ └── race_helpers.verse # the SHARED module
└── Devices/
└── cove_race_manager.verse # our creative_device
The folder Core automatically becomes a module named Core. Anything public we declare in race_helpers.verse is reachable from anywhere with using { /YourProject/CoveRace/Core } (the exact path matches your project's root path). For this article we'll show the full manager device that imports and uses that shared module.
First, the shared module file Core/race_helpers.verse — no class here, just reusable public definitions:
# File: Core/race_helpers.verse — this folder IS the "Core" module
# A localized banner other files can reuse (message needs <localizes>, never a raw string)
RaceBanner<localizes>(Name:string):message = "{Name} leads the cove race!"
# Shared scoring rule: how many increments a checkpoint is worth
CheckpointValue<public>:int = 3
# A tiny helper other files call to decide a winner
HasWon<public>(Points:int)<transacts><decides>:void =
Points >= 10
Now the device file Devices/cove_race_manager.verse imports that module and drives the real devices:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/UI }
# On a bright cel-shaded cove: dock checkpoints grant score, a banner names the leader.
cove_race_manager := class(creative_device):
# Placed score_manager_device: grants points when a checkpoint is hit
@editable
Scorer : score_manager_device = score_manager_device{}
# Placed player_reference_device: tracks the current leader agent
@editable
LeaderRef : player_reference_device = player_reference_device{}
# Localized banner reused from our thinking — declared locally for the demo
RaceBanner<localizes>(Name:string):message = "{Name} leads the cove race!"
OnBegin<override>()<suspends>:void =
# Wake both devices up
Scorer.Enable()
LeaderRef.Enable()
# When the score device awards points, remember who scored as the leader
Scorer.ScoreOutputEvent.Subscribe(OnScored)
# When the leader changes, react
LeaderRef.AgentUpdatedEvent.Subscribe(OnLeaderUpdated)
# Handler: someone crossed a dock checkpoint and got points
OnScored(Agent:agent):void =
# Register this agent as the tracked leader in the reference device
LeaderRef.Register(Agent)
# Bump the score amount awarded by the next activation
Scorer.Increment(Agent)
# Handler: the reference device confirmed a new leader
OnLeaderUpdated(Agent:agent):void =
Print(RaceBanner("Racer"))
Line by line: the two @editable fields let us wire the placed devices in the UEFN editor — without a field, calling Scorer.Enable() would fail with Unknown identifier. In OnBegin we Enable() both devices and Subscribe to two real events: ScoreOutputEvent fires when the score manager awards points, and AgentUpdatedEvent fires when the player reference device stores a new agent. OnScored calls LeaderRef.Register(Agent) — the real method that stores that agent as the tracked player — then Scorer.Increment(Agent) to raise the next payout. When the register succeeds, AgentUpdatedEvent fires and OnLeaderUpdated prints our localized banner.
The module lesson: RaceBanner, CheckpointValue, and HasWon all live in Core/. Any other device on the island — a finish-line teleporter, a UI billboard — can using { .../Core } and reuse them without redeclaring. The folder made the module; the using made it available.
Common patterns
Pattern 1 — Reset the whole race from one shared entry point. A folder module often holds a single "reset" idea called by many devices. Here the manager calls Reset() on the score device:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
cove_reset_manager := class(creative_device):
@editable
Scorer : score_manager_device = score_manager_device{}
OnBegin<override>()<suspends>:void =
Scorer.Enable()
# When max triggers hit, wipe the score back to its starting state
Scorer.MaxTriggersEvent.Subscribe(OnMaxed)
OnMaxed(Agent:agent):void =
Scorer.Reset(Agent)
Pattern 2 — Clear the tracked leader when the round flips. The player reference device's Clear() and AgentReplacedEvent keep the cove leaderboard honest:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
cove_leader_reset := class(creative_device):
@editable
LeaderRef : player_reference_device = player_reference_device{}
OnBegin<override>()<suspends>:void =
LeaderRef.Enable()
LeaderRef.AgentReplacedEvent.Subscribe(OnReplaced)
OnReplaced(Agent:agent):void =
# A new racer took the lead; clear stale state on the old reference
LeaderRef.Clear()
Pattern 3 — Check who is referenced before granting a bonus. IsReferenced is a <decides> query — use it inside if:
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
cove_bonus_manager := class(creative_device):
@editable
Scorer : score_manager_device = score_manager_device{}
@editable
LeaderRef : player_reference_device = player_reference_device{}
OnBegin<override>()<suspends>:void =
Scorer.Enable()
LeaderRef.Enable()
Scorer.ScoreOutputEvent.Subscribe(OnScored)
OnScored(Agent:agent):void =
# Only give the bonus activation if this agent is the tracked leader
if (LeaderRef.IsReferenced[Agent]):
Scorer.Activate(Agent)
Gotchas
- A folder becomes a module automatically — but the path must be exact. The
using { /YourProject/Core }path is built from your project's root plus every folder name. Rename a folder and every importing file'susingmust change too; module paths are permanent addresses, so a typo reads as Unknown identifier. - Files in the same folder need no import.
game_manager.verseandrace_helpers.verseboth inCore/share a namespace and see each other's public definitions directly. Only reach across folders withusing. messageparams are localized, not strings.Print(RaceBanner("Racer"))works becauseRaceBanneris declared<localizes>and returns amessage. There is noStringToMessage— declare a<localizes>function.IsReferencedandHasWonare<decides>— call them in a failure context. Useif (LeaderRef.IsReferenced[Agent]):, not as a plain statement.- You must declare devices as
@editablefields. A barescore_manager_device.Enable()never compiles; wire a placed device into a field first. - Unwrap
?agentfromlistenable(?agent)events. The device events here hand you a plainagent, but some engine events give?agent— then you mustif (A := Agent?):before use.