Overview
Scene Graph is Verse's unified structure that connects every object on your island. Instead of placing finished devices, you assemble entities out of components — small, re-usable building blocks of data and logic. A component is the abstract base class every one of these blocks inherits from.
Two components you'll reach for constantly on any sunny dock scene:
transform_component— stores where an entity sits, how it's rotated, and how big it is. Nearly every visible entity needs one; alight_componentdepends on it to know where to shine.light_component— the abstract base for lights (directional_light_componentfor sunlight,spot_light_componentfor a lantern cone,sphere_light_componentfor a glowing buoy, etc.). It'senableable, so you can flip it on and off.
Reach for these when you want a custom, self-contained object — a swinging lantern, a torch on the clifftop, a glowing treasure chest — that you can turn into a prefab and reuse across the island. Because components run in both edit and play mode, the classic Verse-device pattern is to place a creative_device, hold @editable references to your Scene Graph entities, and in OnBegin walk their components with GetComponents() / GetComponent[] to drive them.
API Reference
component
Base class for authoring logic and data in the SceneGraph. Using components you can author re-usable building blocks of logic and data which can then be added to entities in the scene. Components are a very low level building block which can be used in many ways. For example: * Exposing engine level concepts like mesh or sound * Adding gameplay capabilities like damage or interaction * Storing an
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse).
component<native><public> := class<abstract><unique><castable><final_super_base>:
transform_component
Stores the transforms for an entity, which are used to position the entity.
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse). Inherited members are merged from component.
transform_component<native><public> := class<final><final_super>(component):
light_component
Base class for light components in the SceneGraph. Dependencies: *
transform_componenton the entity positions the light. Examples of components implementinglight_component: *directional_light_component*capsule_light_component*sphere_light_component*rect_light_component*spot_light_component
Full public surface, resolved verbatim from the live Epic digest (Verse.digest.verse). Inherited members are merged from component.
light_component<native><public> := class<abstract><final_super><epic_internal>(component, enableable):
Walkthrough
The moment: A pirate-ship lantern hangs over the cove. When a player steps on the deck trigger, we find the lantern entity, grab its light_component, enable it, and nudge its transform_component up a hair so it swings into place — all from a Verse device.
The key idea: you can't call a bare Entity.Method() on a placed thing. You declare @editable fields on a creative_device, then in OnBegin you query the entity's components with the real Scene Graph API (GetComponents(), GetComponent[]).
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }
using { /Verse.org }
using { /Verse.org/SceneGraph }
using { /Verse.org/SceneGraph/CollisionProfiles }
# Device that lights the pirate-ship lantern when a player steps on the deck plate.
lantern_lighter_device := class(creative_device):
# The deck trigger the player steps on.
@editable
DeckPlate : trigger_device = trigger_device{}
# The lantern ENTITY placed in the Scene Graph. Assign it in the Details panel.
@editable
LanternEntity : entity = entity{}
OnBegin<override>()<suspends>:void =
# Subscribe our handler to the deck plate.
DeckPlate.TriggeredEvent.Subscribe(OnDeckStepped)
# Runs every time an agent steps on the deck plate.
OnDeckStepped(Agent : ?agent):void =
# Turn the lantern's light on.
LightTheLantern()
LightTheLantern():void =
# Find the light_component on the lantern entity and enable it.
if (Light := LanternEntity.GetComponent[light_component]):
Light.Enable()
# Nudge the lantern up 20cm so it swings into its lit position.
# Get/SetLocalTransform are extension methods on the ENTITY - they
# read and write its transform_component's data under the hood.
Current := LanternEntity.GetLocalTransform()
Raised := transform:
Translation := Current.Translation + vector3{ Forward := 0.0, Left := 0.0, Up := 20.0 }
Rotation := Current.Rotation
Scale := Current.Scale
LanternEntity.SetLocalTransform(Raised)
Line by line:
- The
usinglines pull in Scene Graph and its collision-profile helpers soentity,component,light_component, andtransform_componentresolve. DeckPlateandLanternEntityare@editablefields — the only way to reference placed things.LanternEntityis a Scene Graphentity, not a device.OnBeginsubscribesOnDeckSteppedto the plate'sTriggeredEvent. Subscription always happens here.OnDeckStepped(Agent : ?agent)is the handler. Alistenable(?agent)event hands you an optional agent; we don't need the agent here so we just kick off the lantern logic.GetComponent[light_component]is a failable lookup ([]), so it lives inside anif. If the lantern really has a light,Light.Enable()(from theenableableinterfacelight_componentimplements) switches it on.GetLocalTransform()/SetLocalTransform()are extension methods on the entity — they read and write the data stored in itstransform_componentunder the hood (the component itself exposes that data as itsLocalTransformfield). We build a newtransformraised 20cm onUpand write it back.
Common patterns
Pattern 1 — Enumerate every component on an entity with GetComponents(). Handy when you're wiring a prefab and want to confirm the pieces are there.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org }
using { /Verse.org/SceneGraph }
using { /Verse.org/SceneGraph/CollisionProfiles }
# Counts the components on the treasure-chest entity when a button is pressed.
chest_inspector_device := class(creative_device):
@editable
InspectButton : button_device = button_device{}
@editable
ChestEntity : entity = entity{}
OnBegin<override>()<suspends>:void =
InspectButton.InteractedWithEvent.Subscribe(OnInspect)
OnInspect(Agent : agent):void =
# GetComponents() returns []component — every direct component on the entity.
Components := ChestEntity.GetComponents()
Print("Chest has {Components.Length} components")
Pattern 2 — Walk child entities with GetEntities() and light each one. A row of clifftop torches, each a child entity of a parent "TorchLine", all switched on at once.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org }
using { /Verse.org/SceneGraph }
using { /Verse.org/SceneGraph/CollisionProfiles }
# Lights every torch child of the TorchLine entity when the round starts.
torch_line_device := class(creative_device):
@editable
TorchLine : entity = entity{}
OnBegin<override>()<suspends>:void =
# GetEntities() returns the DIRECT child entities of TorchLine.
for (Torch : TorchLine.GetEntities()):
if (Light := Torch.GetComponent[light_component]):
Light.Enable()
Pattern 3 — Slide an entity along the dock by rewriting its local transform. GetLocalTransform()/SetLocalTransform() on the entity read and rewrite the data its transform_component stores, repositioning a floating buoy.
using { /Fortnite.com/Devices }
using { /Verse.org/Simulation }
using { /Verse.org/SpatialMath }
using { /Verse.org }
using { /Verse.org/SceneGraph }
using { /Verse.org/SceneGraph/CollisionProfiles }
# Nudges a buoy entity 100cm forward when a trigger fires.
buoy_pusher_device := class(creative_device):
@editable
PushTrigger : trigger_device = trigger_device{}
@editable
BuoyEntity : entity = entity{}
OnBegin<override>()<suspends>:void =
PushTrigger.TriggeredEvent.Subscribe(OnPush)
OnPush(Agent : ?agent):void =
Old := BuoyEntity.GetLocalTransform()
New := transform:
Translation := Old.Translation + vector3{ Forward := 100.0, Left := 0.0, Up := 0.0 }
Rotation := Old.Rotation
Scale := Old.Scale
BuoyEntity.SetLocalTransform(New)
Gotchas
component,light_componentare abstract. You never construct a barecomponent{}. On placed entities you query for the concrete one you need withGetComponent[light_component](which resolves to adirectional_light_component,spot_light_component, etc. underneath).GetComponent[...]is failable — always in anifor withor. WritingEntity.GetComponent[light_component].Enable()at statement level won't compile; wrap it:if (L := Entity.GetComponent[light_component]) { L.Enable() }.light_componentneeds atransform_component. A light with no transform on its entity has nowhere to shine from. If your lantern goes dark, confirm the entity actually has a transform component.- Entities are NOT devices. You can't call device methods (
Enable,Show) on anentity. You act on its components. And you still need acreative_devicewith@editablefields to hold references to them. - Components run in edit AND play mode. Logic you put directly in a custom component fires the moment you launch the session. If you want play-only behavior, drive it from a
creative_device'sOnBegin, as every example above does. vector3fields areForward,Left,Up— not X/Y/Z. Scene Graph's/Verse.org/SpatialMathvector uses named axes:vector3{ Forward := 100.0, Left := 0.0, Up := 20.0 }.intandfloatdon't auto-convert. Transform translations arefloatvectors — write20.0, never20.- Don't pass raw strings where a
messageis required. If a UI call wants amessage, declareMyText<localizes>(S:string):message = "{S}"and passMyText("...")— there is noStringToMessage.