| name | ue-sequencer-cinematics |
| description | Use this skill when working with Sequencer, LevelSequence, cutscene, cinematic, camera, movie scene, sequencer event, or Movie Render Queue in Unreal Engine. See references/sequencer-patterns.md for dialogue cutscene, in-game camera, and scripted event patterns. For animation playback, see ue-animation-system. |
| metadata | {"version":"1.0.0"} |
Skill: ue-sequencer-cinematics
You are an expert in Unreal Engine's Sequencer and cinematic systems.
Context Check
Read .agents/ue-project-context.md before writing any cinematic code for:
- Target UE version (API availability varies — SequencePlayer property deprecated in 5.4+)
- Cinematic requirements (cutscenes, in-game cameras, offline rendering)
- Multiplayer context (sequence replication behavior differs)
- Build.cs modules already declared
Information Gathering
Ask for:
- Cinematic type: full-screen cutscene, in-game camera, or background ambient sequence
- Whether actors bind at runtime or are pre-placed in the level
- Whether camera control must return to the player after playback
- One-shot or looping sequence
- Real-time gameplay or offline Movie Render Queue output
Build.cs Modules
PublicDependencyModuleNames.AddRange(new string[]
{
"LevelSequence", "MovieScene", "CinematicCamera",
});
PrivateDependencyModuleNames.Add("MovieRenderPipelineCore");
Playing Level Sequences
ALevelSequenceActor — World-Placed
ALevelSequenceActor owns the player. Use GetSequencePlayer() — the direct SequencePlayer
property is deprecated since UE 5.4.
ULevelSequencePlayer* Player = SeqActor->GetSequencePlayer();
if (Player) { Player->Play(); }
ULevelSequencePlayer::CreateLevelSequencePlayer — Runtime Spawn
FMovieSceneSequencePlaybackSettings Settings;
Settings.bAutoPlay = false;
Settings.PlayRate = 1.0f;
Settings.LoopCount.Value = 0;
Settings.bDisableMovementInput = true;
Settings.bDisableLookAtInput = true;
Settings.bHidePlayer = false;
Settings.bHideHud = false;
Settings.bDisableCameraCuts = false;
Settings.bPauseAtEnd = false;
Settings.FinishCompletionStateOverride =
EMovieSceneCompletionModeOverride::ForceRestoreState;
ALevelSequenceActor* OutActor = nullptr;
ULevelSequencePlayer* Player = ULevelSequencePlayer::CreateLevelSequencePlayer(
this, Sequence, Settings, OutActor);
ActiveSequenceActor = OutActor;
if (Player)
{
Player->OnFinished.AddDynamic(this, &AMyClass::OnCutsceneFinished);
Player->Play();
}
Play Control (UMovieSceneSequencePlayer base)
Player->Play();
Player->PlayReverse();
Player->PlayLooping(-1);
Player->Pause();
Player->Stop();
Player->StopAtCurrentTime();
Player->GoToEndAndStop();
Player->SetPlayRate(0.5f);
Player->SetPlaybackPosition(
FMovieSceneSequencePlaybackParams(FFrameTime(120), EUpdatePositionMethod::Jump));
Player->PlayTo(
FMovieSceneSequencePlaybackParams(FFrameTime(240), EUpdatePositionMethod::Play),
FMovieSceneSequencePlayToParams());
Player->SetFrameRange(0, 60);
Player->SetTimeRange(0.0f, 2.5f);
bool bPlaying = Player->IsPlaying();
FQualifiedFrameTime Now = Player->GetCurrentTime();
FQualifiedFrameTime Dur = Player->GetDuration();
Player->OnFinished.AddDynamic(this, &UMyClass::OnSeqFinished);
Player->OnPlay.AddDynamic(this, &UMyClass::OnSeqPlay);
Player->OnStop.AddDynamic(this, &UMyClass::OnSeqStop);
Player->OnNativeFinished.BindUObject(this, &UMyClass::OnNativeFinished);
LsPlayer->OnCameraCut.AddDynamic(this, &UMyClass::OnCameraCut);
Player->SetCompletionModeOverride(EMovieSceneCompletionModeOverride::ForceRestoreState);
Player->Stop();
FLevelSequencePlayerSnapshot Snap;
Player->TakeFrameSnapshot(Snap);
Actor Binding
Tag bindings in Sequencer (right-click object binding -> Tags...) then override at runtime.
Always bind before calling Play().
Spawnables vs Possessables
Possessables bind to pre-existing world actors (placed in level or spawned by gameplay). Spawnables are actors the sequence itself creates and destroys.
FMovieSceneObjectBindingID BindingID = ;
ALevelSequenceActor* SeqActor = ;
SeqActor->SetBinding(BindingID, {SpawnedActor});
Why this matters: Use possessables for persistent world actors (doors, elevators) and spawnables for transient cutscene-only actors (cinematic-only characters, props). Possessables survive sequence end; spawnables are cleaned up automatically.
SeqActor->SetBindingByTag(FName("Hero"), TArray<AActor*>{ HeroActor },
false);
SeqActor->SetBinding(HeroBindingID, TArray<AActor*>{ HeroActor }, false);
SeqActor->AddBindingByTag(FName("NPC"), NpcActor, true);
SeqActor->RemoveBindingByTag(FName("NPC"), NpcActor);
SeqActor->ResetBinding(HeroBindingID);
SeqActor->ResetBindings();
FMovieSceneObjectBindingID ID = SeqActor->FindNamedBinding(FName("Hero"));
const TArray<FMovieSceneObjectBindingID>& All = SeqActor->FindNamedBindings(FName("NPC"));
TArray<UObject*> Bound = Player->GetBoundObjects(HeroBindingID);
Camera System
ACineCameraActor / UCineCameraComponent
ACineCameraActor* Cam = GetWorld()->SpawnActor<ACineCameraActor>(SpawnTransform);
UCineCameraComponent* CC = Cam->GetCineCameraComponent();
FCameraFilmbackSettings FB;
FB.SensorWidth = 36.0f; FB.SensorHeight = 24.0f;
CC->SetFilmback(FB);
CC->SetCurrentFocalLength(50.0f);
CC->SetCurrentAperture(2.0f);
FCameraFocusSettings FS;
FS.FocusMethod = ECameraFocusMethod::Manual;
FS.ManualFocusDistance = 500.0f;
FS.bSmoothFocusChanges = true;
CC->SetFocusSettings(FS);
Cam->LookatTrackingSettings.bEnableLookAtTracking = true;
Cam->LookatTrackingSettings.ActorToTrack = TargetActor;
Cam->LookatTrackingSettings.LookAtTrackingInterpSpeed = 5.0f;
Cam->LookatTrackingSettings.RelativeOffset = FVector(0, 0, 90.f);
SeqActor->PlaybackSettings.bDisableCameraCuts = true;
APlayerController* PC = GetWorld()->GetFirstPlayerController();
PC->SetViewTargetWithBlend(PC->GetPawn(), 0.5f, VTBlend_Cubic);
PC->SetIgnoreMoveInput(false);
PC->SetIgnoreLookInput(false);
APlayerCameraManager
APlayerCameraManager (accessed via PlayerController->PlayerCameraManager) manages camera
blending and view target selection for the local player. After a cutscene ends, restore the
gameplay camera explicitly — Sequencer does not do this automatically:
APlayerController* PC = GetWorld()->GetFirstPlayerController();
PC->SetViewTargetWithBlend(PC->GetPawn(), 0.5f, VTBlend_Cubic);
Sequencer Events
Event tracks call UFUNCTIONs on objects in the event context.
Default event context: UWorld + ALevelScriptActor.
UFUNCTION(BlueprintCallable, Category = "Cinematics")
void TriggerExplosion()
{
ExplosionSystem->SpawnExplosion(ExplosionLocation);
}
Player->PlayTo(
FMovieSceneSequencePlaybackParams(FFrameTime(60), EUpdatePositionMethod::Play),
FMovieSceneSequencePlayToParams());
FMovieSceneEvent
FMovieSceneEvent holds the event endpoint data — the bound function to call when the event
fires. Event tracks are structured as:
UMovieSceneEventTrack — the master track added to a binding or as a master track
UMovieSceneEventTriggerSection — a section containing one or more trigger entries
FMovieSceneEvent — each entry inside the trigger section, pointing to the endpoint function
The endpoint function is resolved at runtime against the event context objects (by default
UWorld and ALevelScriptActor). Director-based events resolve against a
ULevelSequenceDirector subclass instance.
ULevelSequenceDirector — Custom Event Context
ULevelSequenceDirector provides a per-sequence scripting context that receives event track
calls. Subclass it (Blueprint or C++) and assign to the LevelSequence asset's Director Class
property. The Director instance is created when the sequence begins playing and destroyed
when it stops — its lifetime matches the sequence player.
#include "LevelSequenceDirector.h"
#include "MySequenceDirector.generated.h"
UCLASS(Blueprintable)
class UMySequenceDirector : public ULevelSequenceDirector
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable, Category = "Cinematics")
void OnDialogueStart(FName SpeakerTag);
UFUNCTION(BlueprintCallable, Category = "Cinematics")
void OnCutsceneChoice(int32 ChoiceIndex);
};
void UMySequenceDirector::OnDialogueStart(FName SpeakerTag)
{
TArray<UObject*> Bound = Player->GetBoundObjects(SpeakerBindingID);
}
Why Director over Level Script: The Director travels with the sequence asset, not the level.
Reusable across maps. Supports per-sequence state (member variables). Level Script events
only work when the sequence is placed in that specific level.
MovieScene Tracks
UMovieScene* MS = SeqActor->GetSequence()->GetMovieScene();
for (int32 i = 0; i < MS->GetPossessableCount(); ++i)
{
const FMovieScenePossessable& P = MS->GetPossessable(i);
}
for (int32 i = 0; i < MS->GetSpawnableCount(); ++i)
{
const FMovieSceneSpawnable& S = MS->GetSpawnable(i);
}
const TArray<UMovieSceneTrack*>& Masters = MS->GetTracks();
const FMovieSceneBinding* B = MS->FindBinding(SomeGuid);
if (B) { for (UMovieSceneTrack* T : B->GetTracks()) { } }
| Track Class | Purpose |
|---|
UMovieScene3DTransformTrack | Transform animation |
UMovieSceneSkeletalAnimationTrack | Skeletal mesh animation |
UMovieSceneEventTrack | Event triggers |
UMovieSceneAudioTrack | Audio |
UMovieSceneFadeTrack | Screen fade |
UMovieSceneCameraCutTrack | Camera cuts |
UMovieSceneSubTrack | Sub-sequences |
UMovieScenePropertyTrack | Arbitrary UPROPERTY animation (base class) |
All track types require MovieSceneTracks in Build.cs.
Custom tracks: subclass UMovieSceneTrack + UMovieSceneSection for domain-specific
animation data. Register via ISequencerModule::RegisterTrackEditor. This is an advanced
pattern — most needs are met by UMovieScenePropertyTrack subclasses.
UMovieScenePropertyTrack animates arbitrary UPROPERTY values on bound objects. Common
concrete subclasses: UMovieSceneFloatTrack (float properties), UMovieSceneBoolTrack
(bool properties), UMovieSceneColorTrack (FLinearColor / FColor properties). Each creates
sections of the matching type (e.g., UMovieSceneFloatSection) that store a FMovieSceneFloatChannel.
Sub-Sequences
UMovieScene* MasterMS = MasterSequence->GetMovieScene();
UMovieSceneSubTrack* SubTrack = MasterMS->AddTrack<UMovieSceneSubTrack>();
FFrameRate DisplayRate = MasterMS->GetDisplayRate();
FFrameNumber Start = (2.0 * DisplayRate).FloorToFrame();
int32 Duration = (5.0 * DisplayRate).FloorToFrame().Value;
UMovieSceneSubSection* SubSection =
SubTrack->AddSequence(ChildLevelSequence, Start, Duration);
SubSection->Parameters.TimeScale = 1.0;
SubSection->Parameters.bCanLoop = false;
UMovieSceneSubTrack is a singleton master track — AddTrack returns the existing one if already present. Binding IDs inside sub-sequences carry a non-zero SequenceID; use FMovieSceneObjectBindingID::ResolveParentIndex when overriding bindings from the root player. Requires MovieSceneTracks module.
Time Dilation and SlowMo
For SlowMo effects during sequences, use Player->SetPlayRate(0.5f) on the sequence player —
this is independent of UGameplayStatics::SetGlobalTimeDilation and does not affect world
physics or other gameplay systems. Combine with a post-process motion blur intensity increase
for cinematic slow motion without disrupting gameplay state.
Movie Render Queue
UMoviePipelineQueue* Queue = NewObject<UMoviePipelineQueue>(this);
UMoviePipelineExecutorJob* Job =
Queue->AllocateNewJob(UMoviePipelineExecutorJob::StaticClass());
Job->Sequence = FSoftObjectPath(MySequence);
Job->Map = FSoftObjectPath(GetWorld());
Job->JobName = TEXT("MyRender");
Job->SetConfiguration(NewObject<UMoviePipelinePrimaryConfig>(Job));
UMoviePipelineQueueEngineSubsystem* QueueSubsystem =
GEngine->GetEngineSubsystem<UMoviePipelineQueueEngineSubsystem>();
QueueSubsystem->RenderQueueWithExecutor(UMoviePipelineInProcessExecutor::StaticClass());
Common Mistakes
Binding after Play: Overrides applied after Play() miss frame 0.
Always SetBinding* before Play().
Multiplayer camera cuts: Camera cuts only affect the local client.
Use SeqActor->SetReplicatePlayback(true) for server-driven sync.
Camera not returning after cutscene: Sequencer does not auto-restore the player camera.
Subscribe to OnFinished and call SetViewTargetWithBlend + re-enable input.
GC of spawned sequence actor: CreateLevelSequencePlayer returns a raw pointer.
Store OutActor in a UPROPERTY() member to prevent garbage collection.
Skipping mid-sequence: Call SetCompletionModeOverride(ForceRestoreState) before Stop()
so actors return to their pre-sequence state.
PIE timing: Avoid wall-clock assumptions; use GetCurrentTime() frame numbers.
Deprecated direct property: SeqActor->SequencePlayer is deprecated since UE 5.4.
Use SeqActor->GetSequencePlayer().
Wrong player instance: Calling Play() on a stale or mismatched ULevelSequencePlayer
pointer (e.g., from a different ALevelSequenceActor in the level) produces no visible effect
or animates the wrong actors. Always retrieve the player from the specific ALevelSequenceActor
that owns the sequence you intend to drive.
Related Skills
ue-actor-component-architecture — actor spawning and component setup for bound actors
ue-animation-system — skeletal animation tracks, AnimMontage integration in Sequencer
ue-cpp-foundations — delegate patterns, UFUNCTION, UPROPERTY
ue-gameplay-framework — PlayerController camera restoration, GameMode flow