Overview
There's a specific kind of magic when a companion NPC feels like yours instead of a generic quest-giver bolted onto a follow path. That's the job of sidekick_component: it wraps mood state, reaction playback, and cosmetic identity into one device so a recruitable NPC can react to the world instead of just standing near it looking decorative.
We built this at the Beached Pirate Galleon, belowdecks, where the First Mate — your first recruit on the island — trails the player into the hold. Three moments needed to land:
- Skeleton crew burst out of the cargo hold. The First Mate should flinch, then go combat-ready, and the HUD should reflect that shift without us hand-authoring a cutscene.
- The player pries open a sea chest. The First Mate should celebrate — but only if it isn't currently mid-swing at a skeleton.
- The moment a player recruits the First Mate, it should stop looking like a generic NPC and start looking like their Sidekick — same skin, same swagger.
Reach for sidekick_component any time a follower needs to emote in response to gameplay events rather than a fixed animation timeline: ambushes, puzzle solves, boss phases, recruitment moments. It's the difference between an NPC that's in the encounter and one that's just standing in the room where the encounter happens.
API Reference
sidekick_component
Component to manage functionality shared by all Sidekick types.
Full public surface, resolved verbatim from the live Epic digest (Fortnite.digest.verse). Inherited members are merged from component.
sidekick_component<native><public> := class<abstract><final_super><epic_internal>(component):
Events (subscribe a handler to react):
| Event | Signature | Description |
|---|---|---|
ChangeMoodEvent |
ChangeMoodEvent<native><public>:listenable(tuple(sidekick_mood, sidekick_mood)) |
Signaled whenever the Sidekick's mood changes, either via the underlying mood system, or an override is applied. Returns the previous and new mood. |
StartPlayReactionEvent |
StartPlayReactionEvent<native><public>:listenable(sidekick_reaction) |
Signaled when the Sidekick starts to play a reaction, returns the reaction that started playing. |
StopPlayReactionEvent |
StopPlayReactionEvent<native><public>:listenable(sidekick_reaction) |
Signaled when the Sidekick ends playing a reaction, returns the reaction that played. |
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
GetMood |
GetMood<public>()<reads>:sidekick_mood |
Get the Sidekick's current mood. |
PlayReaction |
PlayReaction<public>(Reaction:sidekick_reaction)<transacts><decides>:void |
Request to play a given reaction on the Sidekick. This reaction is not guaranteed to play immediately; instead, the StartPlayReactionEvent should be used to monitor this. This will fail if the Sidekick cannot play the given reaction. |
Entity |
Entity<native><public>:entity |
The parent entity of this component. * Components must have a parent entity pointer provided when being constructed. * Components cannot be moved between parents. |
RemoveFromEntity |
RemoveFromEntity<native><final><public>():void |
Removes the component from the entity. * Removed components are removed from the scene and can only be added back to the same entity. * Flows through OnEndSimulation-> OnRemovingFromScene. |
IsInScene |
IsInScene<native><final><public>()<reads><decides>:void |
Succeeds if the component is currently in the scene. * After OnAddedToScene is called this call succeeds. * After OnRemovingFromScene is called this call fails. |
IsSimulating |
IsSimulating<native><final><public>()<reads><decides>:void |
Succeeds if the component is currently simulating. * After OnBeginSimulation is called this call succeeds. * After OnEndSimulation is called this call fails. |
SendDown |
SendDown<native><native_callable><final><public>(SceneEvent:scene_event):logic |
Send a scene event to this component, invoking OnReceive. Returns true if any participant consumed the event. |
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>:
Methods (call these to make the device act):
| Method | Signature | Description |
|---|---|---|
Entity |
Entity<native><public>:entity |
The parent entity of this component. * Components must have a parent entity pointer provided when being constructed. * Components cannot be moved between parents. |
RemoveFromEntity |
RemoveFromEntity<native><final><public>():void |
Removes the component from the entity. * Removed components are removed from the scene and can only be added back to the same entity. * Flows through OnEndSimulation-> OnRemovingFromScene. |
IsInScene |
IsInScene<native><final><public>()<reads><decides>:void |
Succeeds if the component is currently in the scene. * After OnAddedToScene is called this call succeeds. * After OnRemovingFromScene is called this call fails. |
IsSimulating |
IsSimulating<native><final><public>()<reads><decides>:void |
Succeeds if the component is currently simulating. * After OnBeginSimulation is called this call succeeds. * After OnEndSimulation is called this call fails. |
SendDown |
SendDown<native><native_callable><final><public>(SceneEvent:scene_event):logic |
Send a scene event to this component, invoking OnReceive. Returns true if any participant consumed the event. |
Walkthrough
Wiring the component to our First Mate agent. Before any of the mood or reaction logic can fire, the device needs to know which NPC it's driving and get its initial state squared away. This is the boilerplate that turns a plain NPC prop into a Sidekick that can hear events.
verse ref=sidekick-component#setup
Reacting to mood shifts automatically. The ambush is scripted at the encounter-trigger level — skeletons climb out of the hold — but we don't want to hand-place "look worried" and "look ready for a fight" as separate timed events. Instead we subscribe to ChangeMoodEvent and let the underlying mood system tell us when it has already decided the First Mate is Worried or has snapped into Combat. When that event fires, we play a short warning stinger and swap the HUD's companion-status icon to match. The mood system already knows about nearby threats; we're just listening and translating that into audio/UI feedback.
verse ref=sidekick-component#mood-react
Firing the chest-opening celebration safely. Here's the part that separates "cute idea" from "shippable feature": when the chest opens, we don't blindly call PlayReaction. We call GetMood first. If the First Mate is still flagged Combat — say a straggler skeleton is still swinging — we skip the celebration entirely rather than have it moonwalk through a sword fight. Only when the mood check comes back clear do we call PlayReaction(sidekick_reaction.Happy) or, for the big chest, PlayReaction(sidekick_reaction.Dance). This guard is cheap insurance against one of the ugliest bugs in companion AI: reactions stomping on combat animations.
verse ref=sidekick-component#reaction-trigger
Syncing VFX and camera to the actual reaction window. Requesting a reaction and a reaction actually playing are two different moments — there's wind-up, and the animation might get pre-empted. So for the Dance reaction specifically, we don't hang our confetti burst and camera nudge off the PlayReaction call. We subscribe to StartPlayReactionEvent to know the dance has truly begun, kick off confetti and a subtle camera push-in right then, and subscribe to StopPlayReactionEvent to tear it all down. This keeps effects perfectly framed to the animation instead of drifting ahead of or behind it.
verse ref=sidekick-component#reaction-sync
Making the First Mate look like your First Mate. On recruitment, we call npc_sidekick_component.ApplyEquippedSidekickCosmetic(Agent), handing it the recruiting player's Agent. It reads whatever Sidekick skin that player has equipped in their locker and applies it straight onto the galleon NPC. Two players recruiting the same First Mate on different islands end up with two visually distinct companions — which is exactly the "no two crews look alike" promise we wanted at this scene.
verse ref=sidekick-component#cosmetics
Cleaning up between encounters. Once the hold is cleared and the chest is looted, we reset mood and reaction state so the First Mate doesn't wander into the next room still flagged Combat or stuck mid-celebration. This region also clears any lingering VFX handles from the reaction-sync step so nothing leaks into the next encounter.
verse ref=sidekick-component#reset
Put together, that's the whole loop — setup, mood-driven feedback, guarded reaction playback, tightly synced effects, cosmetic identity, and a clean reset — sitting in one device:
verse ref=sidekick-component
Gotchas
- Don't gate on
PlayReactionsuccess alone. CallingPlayReactiontells the system what you want to happen; it doesn't guarantee the animation is playing this frame. Any effect that needs to be visually locked to the reaction (confetti, camera moves, sound one-shots timed to a beat) belongs onStartPlayReactionEvent/StopPlayReactionEvent, not on the call site. - Check mood before every celebratory reaction, not just once. A skeleton ambush can restart mid-chest-opening animation if your encounter trigger is timing-sensitive. Cache a stale mood read and you'll get a First Mate dancing while getting hit — call
GetMoodright beforePlayReaction, not earlier in the frame. - Cosmetic application needs the right Agent.
ApplyEquippedSidekickCosmeticreads the recruiting player's locker, not whoever's currently closest to the NPC. If your recruitment trigger passes the wrong Agent (e.g. a generic "nearest player" query instead of the one who actually accepted the recruit prompt), you'll get a First Mate wearing a stranger's skin. - Reset state on scene exit, not just encounter clear. If a player leaves the hold mid-combat mood and re-enters, an un-reset
sidekick_componentwill still think it's inCombat, silently swallowing your next celebration reaction and leaving players wondering why the chest cheer never fires. - Don't stack Dance and Happy reactions. Both can be valid responses to a chest, but firing both back-to-back without waiting for
StopPlayReactionEventon the first can visually stutter the NPC. Pick one per celebration trigger, or explicitly queue the second behind the stop event.