Verse Wiki — an interactive Verse handbook for the Unreal Engine & UEFN ecosystem
Chapter 1 · Lesson 3
Comments, Modules & using: Notes for Humans, Boxes for Tools
You've now copied those three using lines twice from the templates in the last two lessons — without ever asking what they do. This lesson pays that debt: first learn to leave notes for humans with # and <# #>, then figure out exactly which toolbox each using hauls in, and decode Verse's domain-style module paths along the way.
1. Comments: Notes to Your Teammates (and to You, Three Months from Now)
Code has two audiences: one is the compiler, the other is people — your teammates, plus the future you who comes back in three months having forgotten every thought you had while writing it. Comments are notes written specifically for that second audience: the compiler skips right over them, they have zero effect on how the program behaves, and yet they rescue countless late nights of "what on earth was this line trying to do."
Verse offers three ways to write comments, each covering its own scenario:
Line comment # — everything from # to the end of the line is a note. It can own a whole line, or tag along after code to add a remark.
Block comment <# … #> — comes as a pair; write as many lines as you like in between. It can even squeeze into the middle of a line of code as an inline note.
Indented comment <#> — below a line starting with <#>, every more-deeply-indented line counts as a comment, and the comment ends as soon as the indentation steps back out. Marking a note's territory with indentation — very much Verse's style.
comment_gallery.verse
# Line comment: everything from # to the end of the line is for humans
MaxPlayers:int = 8 # it can also tag along after code
<# Block comment: write as many lines as you like,
it only ends at the closing marker #>
Total:int = 1 <# it can even squeeze into the middle of a line #> + 2
<#>
Indented comment: this block is indented deeper than the marker above,
so the whole thing is a note — the compiler reads not a single word.
(Blueprint view: in Blueprints you leave notes by dragging out a gray Comment box, or right-clicking a node to add a Node Comment. Verse has no boxes to drag — instead you type the markers #, <# #>, and <#> straight into the code. The form changed, the job didn't: for human eyes only, treated as thin air at Compile time.)
"Comments never execute" is the kind of fact better witnessed than memorized. The device below has a chunk of old code buried inside a block comment — click "Run next step" and see whether it ever gets a scene:
memo_device.verse
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
# This device does exactly one thing: prove that comments never run
memo_device := class(creative_device):
OnBegin<override>()<suspends>:void =
Print("Step 1: boot self-check") # end-of-line comment, leaves the left side alone
<# This old line has been retired; the compiler won't even look:
Print("I am the commented-out code")
#>
Sleep(1.0)
Print("Step 2: comments stayed offstage the whole time")
▶
Output log
Click "Run next step" and watch the code execute line by line.
One side note: the community often says block comments can nest inside each other, but the behavior varies between versions, so this course won't rely on that feature — for the exact nesting rules, defer to the Verse API Reference. If you really need to wrap content containing #>, run a Build first and verify for yourself.
2. Modules: The Code World's Compartmentalized Tool Wall
Picture a wall covered in tools: if the hammers, screws, band-aids, and potato chips all pile into one big crate, finding anything takes forever. Real project code is the same — devices, characters, random numbers, UI: cram hundreds or thousands of definitions into one namespace and you get name clashes, misuse, and things you can never find.Real projects are the same — devices, characters, random numbers, UI: stuff hundreds of Blueprints and assets into a single giant drawer with no naming scheme and you get duplicate names, grabbing the wrong asset, and never finding anything. Verse's answer is the module: pack related definitions into one box — a box with a name, a boundary, and the ability to be picked up and reused as a whole.
The official definition of a module is rather solemn: "A Verse module is an atomic unit of redistributable, dependable code that can evolve over time without breaking its dependents." In plain speech: a module is the smallest unit for shipping an API — Epic can upgrade a module's internals while your code keeps running untouched. Every official capability you use in UEFN — every device, every function — lives in some module; and every folder under your own project's Verse directory automatically becomes a module of the same name too (that's the key to organizing multi-file projects — the extra pages have the full walkthrough).
So step one of "writing Verse" is always: figure out which box the thing you need lives in, then haul that box over — and hauling the box is exactly what using does.
3. using: Hauling the Toolbox onto the Workbench
using has exactly one syntax, and not a single curly brace is optional:
A typical file opening
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /UnrealEngine.com/Temporary/Diagnostics }
What it does: it brings the public definitions of the given module into the current file, so you can call things by their short names — write creative_device instead of the full path every time. You can survive without using — fully qualified names still work — but nobody wants to recite an address on every line. By convention, all using lines sit at the top of the .verse file, like flashing your loadout at the start of a match.
What it does: it pulls in everything the given module (that tool drawer) exposes to the outside, all in one go, so you can just write the short name creative_device instead of chanting the full-length address every time. It's the same move as ticking a plugin on for your project, or pulling an asset folder into scope. You can survive without using — reciting the entire long path from memory still works — but nobody enjoys doing that on every line. By convention, all the using lines stack up at the very top of the .verse file, like laying out your whole loadout at match start.
Here's what the common paths cover. Just get acquainted for now — come back and look things up whenever you forget:
Module path
What it covers
Notable members
/Fortnite.com/Devices
The creative_device base class plus every built-in device
creative_device, button_device
/Fortnite.com/Characters
Game characters
fort_character
/Fortnite.com/Game
General definitions for the Fortnite gameplay layer
—
/Verse.org/Simulation
Time and simulation
Sleep
/Verse.org/Random
Random numbers
GetRandomInt, GetRandomFloat
/Verse.org/Colors
Colors
color
/UnrealEngine.com/Temporary/Diagnostics
Debug logging tools
the log logging class
/UnrealEngine.com/Temporary/SpatialMath
Spatial math
vector3
/UnrealEngine.com/Temporary/UI
User interface
—
Notice anything? These paths look like URLs: they start with /, and the top level is an internet domain — Fortnite.com, Verse.org, UnrealEngine.com. That's a deliberate design — the domain marks who owns the API and what stability it promises: /Verse.org is language- and general-runtime-level capability, /Fortnite.com belongs to the Fortnite ecosystem, /UnrealEngine.com comes from the engine side. And the Temporary segment in a path is Epic saying out loud that "these APIs are in temporary housing and will move someday" — so don't panic when you see it, and don't be shocked if a using needs updating one day. One more bit of trivia: Print itself lives in the /Verse.org/Verse module, which is available without an explicit using — that's why the first two lessons never wrote an import for Print; what the Diagnostics line in the template actually provides is debug tooling like the log logging class.
Hands-on time: the opening of the "nap device" below has two words carved out — one is the keyword that hauls toolboxes, the other is the module Sleep lives in. Fill them back in, then hit "Check answers":
(Reading the graph: this device equals an Event BeginPlay wired to a Print String "Napping for 3 seconds..." → a 3-second Delay → another Print String "Awake!"; those using lines at the top simply tick open the drawers where Delay and the string printing live.)
nap_device.verse
____ { /Fortnite.com/Devices }
using { /Verse.org/____ }
using { /UnrealEngine.com/Temporary/Diagnostics }
nap_device := class(creative_device):
OnBegin<override>()<suspends>:void =
Print("Napping for 3 seconds...")
Sleep(3.0)
Print("Awake!")
4. Building a Module of Your Own: Just a First Hello
You can use other people's modules — now stake out a patch of your own. The most direct way is a module expression:The most direct way is to hand-write a small module declaration and open a brand-new drawer for yourself:
tools.verse
# Stake out a patch by hand with a module expression
tools<public> := module:
Greet<public>():void =
Print("Greetings from the tools module")
(Reading the graph: the snippet above creates a new tool drawer called tools holding one Blueprint function Greet, whose body is a single Print String; the two <public> marks hang a "visible to the outside" sign on the drawer and on the function respectively.)
After that, using { tools } in another file lets you call Greet() directly; without the import, the qualified tools.Greet() reaches it too.After that, write using { tools } in another file (pulling the tools drawer open) and you can call Greet() directly; too lazy to open the drawer, the full name tools.Greet() finds it too. The other, more common road is the implicit module: every folder under your project's Verse directory automatically becomes a module of the same name — making a folder is making a module, zero lines of code required.
Those <public> angle brackets on the code are visibility specifiers.Those <public> angle brackets on the code do exactly what the Public / Protected / Private access setting does for variables and functions in Blueprint — Verse just writes it as angle brackets hanging off the name. Verse has four levels: public (anyone can use it), internal (the default — current module only), protected (the class and its subclasses), and private (the current class only). Only one iron rule matters right now: for code outside the module to use a member, both the module and the member must be marked <public> — miss either one and the caller slams into an access error. The full craft of organizing modules, nesting, and visibility waits for the advanced chapters after Lesson 16; a passing acquaintance is plenty for today.
5. Classic Pitfalls: The Moment You Forget using
Pitfall 1: forget the using, collect an "Unknown identifier". This is the number-one accident in a fresh blank .verse file: you eagerly type my_device := class(creative_device):, hit Build, and the compiler throws back "Unknown identifier" — it has no idea what creative_device is. The reason is simple: creative_device isn't a keyword, just a class inside the /Fortnite.com/Devices module; if the toolbox never got hauled in, the tools inside it don't exist. From now on, whenever you see Unknown identifier, your first reflex should be: am I missing a using line?
Pitfall 2: using without the curly braces. Writing using /Fortnite.com/Devices is a straight-up syntax error. The braces are part of the using syntax, not decoration.
Pitfall 3: a block comment left unclosed. You wrote the <# and forgot the #>, and a long stretch of perfectly good code gets swallowed as a comment. Even sneakier: the error usually points somewhere far down the file, miles away from the actual crime scene. When you see baffling errors across a wide area, go back and hunt for an unclosed <#.
Pitfall 4: casually renaming a folder. Folders are modules — renaming or moving a folder changes the module path. Best case, a string of using lines breaks; worst case, Verse devices already placed in your level lose their class references. Before renaming, first ask how many places point at it.
One more thing: importing nested modules is order-sensitive — import the outer module first, then the submodule; the reverse errors out. That pitfall, along with the complete playbook for cross-folder references, lives in this lesson's extra page.
6. Level Challenges
Three little challenges to bank this lesson's loot. Wrong answers cost nothing — retry as often as you like.
You create a blank .verse file, write nothing at the top, go straight to my_device := class(creative_device): and hit Build. What happens?
You want to comment out a big chunk of old code in one piece. Which syntax should you use?
Your code calls Sleep(2.0), and Build reports "Unknown identifier". Which using line is most likely missing?
Further Reading
Deep Dive · EXTRA
The digest Files: An API Dictionary Fresher Than the Docs Site
The .digest.verse files generated on every build are a complete API inventory in strict sync with your local version — a veteran's first stop for API lookups.
Referencing Your Own Modules Across Folders, the Right Way
A quick-reference for using syntax across same-directory, subfolder, and nested-module scenarios — plus the iron rule of outer-module-first import order.