The Rules That Keep Verse Honest
Tutorial beginner compiles

The Rules That Keep Verse Honest

Updated beginner Fundamentals Code verified

The Rules That Keep Verse Honest

You've now read the whole grammar: sentences, shape, nouns, and verbs. This final lesson is different. It's not new grammar — it's the rules of good conduct: the handful of conventions that separate Verse code that works and lasts from code that fights you.

These rules come straight from how Verse is written on real shipping projects. Each one has a why — and once you understand the why, you can also use the rule to direct an AI helper correctly, because you'll know what good code is supposed to look like and you'll spot it when the AI gets it wrong. That second skill is worth as much as the first.

Rule 1: Use real APIs only — never invent names

<!-- section-art:rule-1-use-real-apis-only-never-invent-names --> The Rules That Keep Verse Honest: Rule 1: Use real APIs only — never invent names

Authentic Key Only

This is the one that matters most, and the one AI helpers break the most.

Every device, type, and function you use must be a real one from the Fortnite, Verse, or Unreal Engine API. You do not get to invent doTheThing() or super_jump_device because it sounds right. If it isn't a real name, the code won't compile — full stop.

# WRONG — these names don't exist; invented out of thin air
MyButton : magic_button_device = magic_button_device{}
MyButton.WhenClicked.Listen(DoStuff)

# RIGHT — real device, real event, real method
MyButton : button_device = button_device{}
MyButton.InteractedWithEvent.Subscribe(OnPressed)

Why: Verse is strict on purpose. It checks every name before the game runs, so a made-up name is caught instantly instead of crashing mid-match. The strictness is a safety net, not a nuisance.

The discipline: when you're not sure a name is real, look it up — that's exactly what the Verse Cortex knowledge base is for. Search it before you write. And when you direct an AI, say so: "use only real Fortnite/Verse APIs; if you're unsure, tell me instead of guessing." AI helpers love to invent plausible-sounding names. The grammar you've learned lets you smell a fake: WhenClicked and Listen read like real Verse, but they aren't — InteractedWithEvent and Subscribe are.

Rule 2: Indentation is meaning — keep it clean

From Part 2: the shape of your code is part of what it does. A line indented under another line lives inside it.

score_keeper := class(creative_device):

    var Score : int = 0

    AddPoint() : void =
        set Score += 1
        Print("Point added")

Why: because the shape carries meaning, a crooked indent isn't an eyesore — it's a bug. Outdent Print by accident and you've changed which box it lives in. Use two spaces per level, consistently, everywhere. Don't mix tabs and spaces.

Directing an AI: if a helper hands you code with ragged indentation, don't accept it — the indentation tells you whether it even means what you asked for. Ask for two-space, consistent indentation, and check the shape against your intent.

Rule 3: Name things for what they are

From Part 3: a good name makes the sentence read itself.

# Good — every name does real work
var PlayersRemaining : int = 0
EliminatePlayer(Target : agent) : void = Print("Eliminated")

# Bad — names that hide what's going on
var n : int = 0
DoIt(a : agent) : void = Print("?")

Why: code is read far more often than it's written. A name like PlayersRemaining is documentation that can never go stale. Vague names (n, flag, DoIt) force every reader — including future-you — to stop and decode. Our project conventions are firm: names must convey purpose.

Directing an AI: precise names are precise instructions. "Make a function EliminatePlayer that takes an agent" leaves no room for confusion. Good naming is the shared vocabulary that lets you and a helper mean the same thing.

Rule 4: Handle "maybe" honestly — options and <decides>

From Parts 3 and 4: some things might not be there (an option, ?type) and some verbs might fail (<decides>). Verse refuses to let you pretend otherwise — you must check before you use.

# A <decides> call can fail, so it uses [ ] and lives in an if
if (FortChar := SomeAgent.GetFortCharacter[]):
    Print("Character is here — safe to use it")
else:
    Print("No character right now — handle the empty case")

Why: the single most common crash in most languages is using something that turned out to be missing — a player who left, a chest that was empty. Verse makes that mistake impossible to ignore: the [ ] and the if force you to deal with both outcomes. Notice you don't write return true from a <decides> function either — the whole function is the test, so you just produce the value or fail. Every empty case you handle is a crash that never happens.

Directing an AI: tell helpers to "handle the failure case explicitly" whenever something can be missing. Sloppy code skips the else; honest code never does.

Rule 5: Be careful when you change game state — <transacts>

From Part 4: a verb that changes the game's state is labeled <transacts>, and set is how you actually move a variable.

Here's the catch our project rules stress: Verse does not undo changes if something fails partway. There's no automatic rewind. So the rule is simple and strict: check everything first, then change things. Validate all your conditions up front; only once they all pass do you start modifying state.

# Validate FIRST, then act — so you never leave the game half-changed
AwardWin(Winner : agent)<transacts> : void =
    if (RoundActive?, not GameOver?):
        set GameOver = true
        set CurrentScore += 1

Why: if you change three things and the fourth fails, the game is left in a broken, half-finished state with no way back. Checking all conditions before the first set means you never start a change you can't finish. (And remember: <transacts> is contagious — a function that calls a <transacts> function must be <transacts> too.)

Directing an AI: "validate all conditions before modifying any state, since Verse has no rollback." This one phrase prevents a whole category of subtle bugs.

Rule 6: Keep each piece focused (and saved data forever-safe)

Two related habits that keep a project healthy as it grows.

One job per piece. A function should do one thing; a module should be about one thing. A score_keeper keeps score — it doesn't also spawn enemies and play music. Small, focused, self-contained pieces are easy to read, easy to fix, and easy to reuse. Our conventions call this single-responsibility and DRY ("don't repeat yourself" — write a thing once and reuse it).

Saved data is sacred. UEFN can persist data between matches (a player's XP, their unlocks). Once players have saved data, there's an iron rule: you may add new saved fields, but you must never remove a field or change its type — doing so corrupts everyone's existing saves. You can grow the save format; you can't break it. (Persistence has its own careful patterns; this is the one principle to carry from day one.)

Why: focused code is code you can still understand in six months, and the save rule protects the one thing players can never get back — their progress.

Directing an AI: "keep functions small and single-purpose" and "never remove or retype existing saved fields — only add." Helpers will happily refactor a save struct into oblivion if you don't say this.

Rule 7: Leave a trail — comments and logs

Two small habits that pay off constantly.

Comments explain why, briefly, where the code isn't obvious. They start with #:

# Storm closes faster in the final phase to force the fight
StormDelay : float = 5.0

Logging lets you see what your code is actually doing while it runs. Print puts a message on screen, which is your simplest window into a running game:

Why: comments rescue the next reader (often you) from re-deriving your reasoning, and logs are how you find out why something misbehaved without guessing. Don't over-comment obvious lines — a well-named noun (Rule 3) already documents itself — but do explain the non-obvious.

Putting it all together

<!-- section-art:putting-it-all-together --> The Rules That Keep Verse Honest: Putting it all together

Verse Harmony

That's the whole foundation. Watch every rule show up in one small, correct device:

using { /Fortnite.com/Devices }   # Rule 1: real module, opened with using
using { /Verse.org/Simulation }    # needed for agent and @editable

# Rule 6: one focused job — this device only manages a simple win condition
win_tracker := class(creative_device):

    @editable
    WinButton : button_device = button_device{}   # Rule 1: real device type

    WinningScore : int = 1                          # Part 3: a constant
    var CurrentScore : int = 0                      # Part 3: a variable

    OnBegin<override>() : void =                    # Part 4: real startup event
        WinButton.InteractedWithEvent.Subscribe(OnWinPressed)  # Rule 1 + Part 4

    # Rule 5: changes state, so <transacts>; validate before acting
    OnWinPressed(Agent : agent)<transacts> : void =
        if (CurrentScore < WinningScore):          # Rule 4: check first
            set CurrentScore += 1                   # then change state
            Print("We have a winner!")             # Rule 7: leave a trail```

Read it top to bottom and you've used *everything*: real APIs (Rule 1), clean two-space shape (Rule 2), names that read themselves (Rule 3), an `if` that checks before acting (Rules 4 & 5), one focused device (Rule 6), and a log line (Rule 7). Nothing here was memorized. It was all *read*, as grammar.

## The whole series, in one breath

- Verse lines are **sentences**: *Name is a Type, starts as Value.*
- The **shape** (indentation) shows what belongs to what.
- **Nouns** are the things you name; **types** are their kinds; **var** marks the ones that change.
- **Verbs** are actions; **events** trigger them (*when X, do Y*); **effect labels** say what a verb may do — wait, fail, or change state.
- And these **rules** keep it all honest: real APIs only, clean shape, clear names, honest failure handling, careful state changes, focused pieces, and a readable trail.

You didn't memorize Verse. You learned to *read* it, *write* it, and *direct others*  human or AI  to do the same. That's the whole craft. Now go build something.

## References

- [Verse Language Reference (Epic)](https://dev.epicgames.com/documentation/en-us/uefn/verse-language-reference)
- [Learn Programming with Verse (Epic)](https://dev.epicgames.com/documentation/en-us/fortnite/learn-programming-with-verse-in-unreal-editor-for-fortnite)
- [Verse Persistable Data (Epic)](https://dev.epicgames.com/documentation/en-us/uefn/persistable-data-in-verse)
- Distilled from the Verse Cortex knowledge base and our project Verse conventions (.cursor/rules: language, formatting, data, error-handling, transacts, persistence, documentation).

Get the complete code — free

You've read the full walkthrough. The complete, copy-paste-ready Verse solution is free for members — sign in to unlock it.

Free with your BrainDead.TV / BrainDeadGuild Discord account. The walkthrough above is always free.

Verse source files

Check your understanding

Test yourself with an interactive quiz and track your progress + earn XP — free for members.

Up next · Devices with Verse Device References: Handing Verse the Remote Control Continue →

Turn this into a guided course

Add Verse language fundamentals — the conventions and rules of good Verse code to your free study plan — we'll suggest related pages and stitch the lot into one compile-checked, self-guided lesson with worked examples and quizzes.

Original tutorial generated by Verse Island from the Verse/UEFN knowledge base, with references to the Epic Games sources above. Code is validated against the knowledge base.

Comments

    Sign in to vote, comment, or suggest an edit. Sign in