Verse Wiki — the Verse handbook for Blueprint authors
Chapter 8 · Lesson 27

Writing a Component: What a Blueprint Component Looks Like as Code

Last lesson's conclusion fits in one line: an entity is an empty container, a component is an ability you drop into it. This lesson drops the worldview talk and gets hands-on — we take a component skeleton apart piece by piece: how the type is declared, how fields are written, how @editable pushes a property into the Details panel, and when each lifecycle callback gets woken up. By the end you'll see that "Add Component" is literally the same action on both sides.

1. A Component Is Just a Class

First, compress last lesson into one sentence you can carry: an entity does nothing on its own; what it can do depends entirely on which components you put in it. A visible block is "entity + mesh_component". A block that glows is "entity + mesh_component + light_component". No inheritance tree, no "subclass of XxxActor" — only assembly.

Which turns the question into: where do abilities come from? The built-in ones (meshes, lights, collision, particles) are already written by Epic — you just pick them off a list. But when your list of desired behaviors has a gap — say "this platform rises every two seconds and then comes back down" — you have to write a component yourself.

The good news is that writing a component means writing a Verse class. The class syntax from Lesson 20 carries over unchanged; only three things are Scene Graph specific: what you inherit from, which specifier you attach, and which lifecycle functions you override. Here is a minimal skeleton that actually runs. Look at it whole first; we'll take it apart in the next section:

hello_component.verse
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }

hello_component<public> := class<final_super>(component):

    @editable
    Greeting<public>:string = "hello"

    OnBeginSimulation<override>():void =
        (super:)OnBeginSimulation()
        Print("{Greeting}")

A dozen lines and a custom component exists. Map it onto what you already know: this is equivalent to creating a new Blueprint whose parent class is Actor Component, adding a String variable Greeting in the variables panel with Instance Editable ticked, and wiring a Print String onto its Event BeginPlay. The only difference: that side is three panels and some wires, this side is one text file.

2. Dissecting the Skeleton: Four Positions Worth Memorizing

▢ Part one: using. Same as Lesson 7 — using is "pull open a drawer". The Scene Graph API lives in /Verse.org/SceneGraph; time-related things like Sleep live in /Verse.org/Simulation; vector3 and transform live in /Verse.org/SpatialMath. When the editor generates a component file from its template these lines are written for you — all you need to know is which missing line makes which batch of names "unrecognized".

▢ Part two: the type declaration. This single line is the densest thing in the lesson:

the declaration, taken apart
hello_component<public> := class<final_super>(component):
#      ▲              ▲          ▲             ▲
#      name       who can use   Scene Graph's  inherits from the
#                    it         hard rule      component base class

▢ Part three: fields. Ordinary Verse fields, written exactly as in Lesson 8. The only new thing is the extra line above them: @editable. With it, the field appears in the Details panel; without it, it is purely internal data. Hold that thought — the next section expands on it.

▢ Part four: lifecycle callbacks. This is the only genuinely new idea in a custom component. A Blueprint Component gives you two or three entry points (Event BeginPlay / Event EndPlay). Verse slices it finer: a component passes through a series of stages from creation to destruction, and each stage has an overridable callback. The official docs list the stages as: Initialized → AddedToScene → BeginSimulation → EndSimulation → RemovingFromScene → Uninitializing. In the Verse API, these are the ones you'll override most:

Callback When it wakes up What it's for
OnAddedToScene() After the component enters the scene From this moment on, queries for other components are valid
OnBeginSimulation() When the component starts simulating; runs to completion immediately One-off setup: find other components once, subscribe to events, cache references
OnSimulate()<suspends> Right after OnBeginSimulation Async logic that needs to wait: loops, Sleep, long-running behavior
OnEndSimulation() When simulation ends Teardown: unsubscribe, cancel cached callbacks
OnRemovingFromScene() Just before the component leaves the scene Only invoked if OnAddedToScene actually ran

Two ordering guarantees are worth burning in: OnBeginSimulation always runs before OnSimulate, and OnSimulate is cancelled before OnEndSimulation. So "prepare" in the former and "perform" in the latter is the officially recommended split.

One more rule that trips people up: overriding requires the <override> specifier, and the first line of the body should call the parent's implementation — written (super:)OnBeginSimulation(). That's the auto-generated Parent node you get when you override an event in Blueprint: you can leave it unwired, but most of the time wiring it is correct.

▢ Bonus: Entity. Every component carries a constant named Entity pointing at the entity that holds it. It's the always-available GetOwner from a Component graph. Moving your own object, finding another component on the same object — everything starts here.

3. @editable: Getting a Property into the Details Panel

Anyone who has shipped Blueprints knows this need cold: a "lift platform" component, and a designer who wants to tune how high it goes and how long it waits. You can't recompile every time a number changes. Blueprint's answer is to tick Instance Editable (the little eye) on the variable, which drops it into the Details panel so every instance placed in the level can hold a different value.

Verse's answer is one extra line above the field: @editable.

editable_demo.verse
editable_demo<public> := class<final_super>(component):

    # Shows up in the Details panel; each instance can hold its own value
    @editable
    Height<public>:float = 200.0

    @editable
    Loops<public>:logic = true

    # No @editable: purely internal data, invisible in the panel
    InternalTag:string = "lift"

Three rules. First, @editable is an attribute — it starts with @ and sits on the line above the field. Don't confuse it with <public> or <final_super>, which are specifiers written inside angle brackets; those are two different systems. Second, an editable field must have a default value, and that value is what the panel shows initially. Third, changing a value on one instance in the level only affects that instance — the official wording is that the change applies to that instance alone, other instances are untouched, and no recompile is needed. That is exactly Instance Editable semantics.

While we're here, let's map the other Blueprint habit: variables also have Expose on Spawn, which adds a wireable input pin to the Spawn Actor node. Verse has no switch by that name — either you fill the value in the Details panel, or you assign the field directly when you construct the instance in code (my_component{ Height := 300.0 }). The latter is what "pass parameters at spawn time" looks like as code.

Which types may be marked @editable, plus range-limited variants like @editable_slider and @editable_number and the syntax for panel categories and tooltips — all of that is collected in this lesson's technique extra.

4. Bolting the Component onto an Entity

The class is written. How do you make it actually do something? The answer is almost insultingly familiar: click Add Component in the Details panel and pick it from the list.

The official flow goes like this: select an entity in the scene, in its Details panel click Add Component > New Verse Component, choose Scene Graph Component from the Verse code templates, type a component name (say my_verse_component), and click Create. UEFN generates the .verse file for you — the skeleton above — and attaches the component to the current entity at the same time. After that you edit the code in VS Code, compile, and the behavior updates.

Once a component compiles, it lives permanently in the Add Component list: any entity in the scene can pick it, no differently from picking mesh_component or light_component. Your abilities and Epic's abilities are equal citizens in that panel.

What you do in Blueprint What you do in Scene Graph
Open an Actor Blueprint, click +Add in the Components panel Select an entity, click Add Component in the Details panel
Pick Static Mesh Component from the list Pick mesh_component from the list
Pick the Actor Component subclass you wrote Pick the Verse component you wrote
Select that Component and fill in parameters on the right Select that component and fill in @editable fields on the right

There is also a code path: entity exposes AddComponents(), letting you attach component instances at runtime. That corresponds to Blueprint's Add Component by Class node — "grow an ability after the game is already running". In day-to-day work, though, the overwhelming majority of components are attached in the editor; code assembly is reserved for genuinely dynamic cases.

One last rule that's easy to miss: an entity may hold only one component of a given class (or its subclasses). Want two meshes on one object? You can't — the correct move is to add a child entity and put the second mesh there. This is a visible break from the Blueprint habit of hanging five Static Mesh Components off one Actor, and it will stop you short the first time you hit it.

5. A Complete Example: A Platform That Rises and Falls

Bolting the first four sections together gives a component you could actually ship: a platform that rises to a given height, waits, comes back down, and repeats. It needs two @editable parameters (how high, how long) and two lifecycle callbacks. Click "Run next step" and watch the component go from attached to performing.

lift_platform_component.verse
using { /Verse.org }
using { /Verse.org/Native }
using { /Verse.org/SceneGraph }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }

lift_platform_component<public> := class<final_super>(component):

    @editable
    Height<public>:float = 200.0

    @editable
    WaitTime<public>:float = 2.0

    OnBeginSimulation<override>():void =
        (super:)OnBeginSimulation()
        Print("Lift platform ready")

    OnSimulate<override>()<suspends>:void =
        loop:
            Entity.SetLocalTransform(transform{Translation := vector3{Up := Height}})
            Sleep(WaitTime)
            Entity.SetLocalTransform(transform{Translation := vector3{Up := 0.0}})
            Sleep(WaitTime)
Output log

Click "Run next step" to watch the code execute line by line.

Read it back: there is not a single line of boilerplate for "register with the engine" or "subscribe to Tick". You overrode two functions; Scene Graph handles the rest — it knows when to call you, exactly the way Blueprint knows when to fire your Event BeginPlay.

Attach this component to an entity that has a mesh_component and you have a moving platform. Attach the same component to ten different entities and fill in a different Height on each one's Details panel and you have ten platforms at ten heights — one piece of code, ten behaviors. That's what "composition over inheritance" looks like on a Tuesday.

A practical heads-up: the official docs note that component logic runs in both edit mode and play mode, meaning any behavior you add starts running the moment you launch your session. That's a different split from Blueprint's Construction Script versus BeginPlay, so the first time you see a platform moving on its own inside the editor, don't file a bug.

Blueprint Cross-Reference

Every action in this lesson has a counterpart you already perform daily. The differences column is the point.

What you do in Blueprint How it's written in Verse Difference
New Blueprint, parent class Actor Component my_component := class<final_super>(component): A Verse component is a .verse text file, not a binary asset — it can be diffed and code-reviewed
Click +Add in the Components panel and pick a component Click Add Component in the Details panel and pick a component Nearly identical. The difference: Scene Graph allows only one instance of a given component class per entity
New variable in the variables panel, tick Instance Editable @editable on the line above the field Same semantics: default value lives in code, each instance can override it in the Details panel
Tick Expose on Spawn on a variable Assign the field at construction: my_component{ Height := 300.0 } Verse has no switch by that name; "parameters at spawn time" becomes part of the construction expression
The Component's Event BeginPlay OnBeginSimulation<override>() Verse splits "entered the scene" and "started simulating" into two callbacks; querying other components has to wait until the scene stage
Event Tick + Timeline for continuous motion loop + Sleep inside OnSimulate<override>()<suspends> Not a per-frame callback but a coroutine that can wait; for genuine per-frame work the component has separate TickEvents callbacks
GetOwner in a Component graph The built-in Entity constant You get an entity rather than an Actor: it has no type of its own, only a pile of components
GetComponentByClass Entity.GetComponent[mesh_component] The Verse version can fail, so it must live in a failure context like an if — there is no "returns null, then Accessed None"
Add Component by Class node Entity.AddComponents(...) Both attach abilities at runtime; in practice both sides usually attach in the editor instead

Why do these differences exist? The root is the fork from Lesson 26: a Blueprint Actor is an inheritance tree with components bolted on; a Scene Graph entity has no tree at all — it is a basket, and all meaning comes from the components inside it. Since everything is composition, the engine has to be extremely explicit about "when is a component available" — hence six lifecycle stages; and it has to treat "component not found" as a normal outcome — hence GetComponent being failable.

Another layer of difference comes from the medium. A visual editor inherently communicates "which parameters are tunable"; in a text file, that has to be stated explicitly by something like @editable. You'll notice that most of Verse's "extra words" buy the same thing: legibility in plain text.

And to repeat this site's factual discipline: Actors and Blueprints are fully supported in UE6 Early Access (targeting late 2027) and the releases after it; deprecation waits until Scene Graph is mature enough, and the timing is undecided. You are learning components not because Blueprint disappears tomorrow, but because this is the same craft written another way — and that way is the new framework's native language.

Challenge Gauntlet

Component written; three checks to pass. Zero penalty for wrong answers, retry as often as you like.

When declaring a custom Scene Graph component, which specifier in the class declaration is a hard requirement of Scene Graph?

You want a loop of "rise, wait two seconds, fall, wait two seconds" inside your component. Which callback should it live in?

Lesson 23 covered it). Which callback is wearing it?">

You want designers to set a different rise height on each platform in the level. What do you do?

Further Reading

Technique · EXTRA

@editable and the Details Panel: Let Artists Tune Your Component

Which types can be exposed, how to constrain sliders and numeric ranges, how to add categories and tooltips, and how defaults relate to level overrides.

Open the extra →

Deep Dive · EXTRA

Asset-Generated Components: How Meshes, Sounds and Particles Become Components

You never wrote a line of it — so where did mesh_component come from? The origins, properties and limits of asset-generated components.

Open the extra →

Advanced · EXTRA

How Components Find Each Other: Communication Inside One Entity

GetComponent versus GetComponents, Epic's "look once, then cache" discipline, and why lookup is riskier than calling in a composition-first architecture.

Open the extra →