ue5-cinematics
UE5 Cinematography & Cutscene Development
Cinematic sequences, virtual camera work, cutscene scripting, and final rendering in Unreal Engine 5 using Sequencer.
Infrastructure
UE5 runs on your UE5 workstation. See ue5-gamedev skill for full infrastructure and API details.
Sequencer operations can be automated via Remote Control API, Python bridge, and MCP tools for camera placement, property keyframing, and render queue management.
The Remote Control API endpoint defaults to http://localhost:8080 but is configurable per your UE5 Remote Control plugin settings (Edit > Project Settings > Plugins > Remote Control).
Sequencer fundamentals
Level Sequence vs Master Sequence
- Level Sequence: Single cinematic clip (one scene, one shot, one take)
- Master Sequence: Orchestrates multiple Level Sequences in order (shot list / edit)
Creating sequences
import unreal
# Create a Level Sequence asset
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
factory = unreal.LevelSequenceFactoryNew()
sequence = asset_tools.create_asset(
"LS_Cutscene_01",
"/Game/Cinematics/Sequences",
unreal.LevelSequence,
factory
)
# Open in Sequencer
unreal.LevelSequenceEditorBlueprintLibrary.open_level_sequence(sequence)
Track types
| Track | Purpose | Common uses |
|---|---|---|
| Actor (Possessable) | Animate existing level actor | Characters, props, lights |
| Actor (Spawnable) | Spawn actor for this sequence only | Temp cameras, FX |
| Camera Cut | Switch active camera | Shot editing |
| Audio | Sound cues and dialogue | Music, VO, SFX |
| Event | Trigger Blueprint events | Gameplay integration |
| Fade | Screen fade in/out | Transitions |
| Subscene | Embed another Level Sequence | Reusable shots |
| Material Parameter | Animate material properties | Dissolves, color shifts |
| Particle | Control Niagara systems | Cinematic VFX |
| Transform | Position/rotation/scale | Any actor movement |
| Property | Keyframe any exposed property | Light intensity, FOV, etc. |
Camera work
Camera types
| Camera | When to use |
|---|---|
| CineCameraActor | Primary cinematic camera. Has filmback, lens, focus settings. |
| CameraActor | Basic camera. Fewer cinematic controls. |
| Camera Rig Rail | Camera dolly on a spline path |
| Camera Rig Crane | Crane arm with boom length and rotation |
CineCameraActor properties
Key properties to keyframe:
Filmback:
SensorWidth: 36.0 -- 35mm full frame (default)
SensorHeight: 24.0 -- Aspect ratio from sensor dimensions
Current Focal Length: 35.0 -- Lens focal length in mm
Wide: 16-24mm
Normal: 35-50mm
Telephoto: 85-200mm
Current Aperture: 2.8 -- f-stop (depth of field)
Deep DOF: f/8 - f/16
Shallow DOF: f/1.4 - f/2.8
Focus Settings:
FocusMethod: Manual / Tracking
ManualFocusDistance: 500.0 -- cm
TrackedActorForFocus: (actor reference)
Current Horizontal FOV: (computed from focal length + sensor)
Common filmback presets
| Format | Sensor Width | Sensor Height | Aspect |
|---|---|---|---|
| 35mm Full Frame | 36.0 | 24.0 | 1.5:1 |
| Super 35 | 24.89 | 18.66 | 1.33:1 |
| IMAX | 70.41 | 52.63 | 1.34:1 |
| Anamorphic 2:1 | 21.95 | 18.6 | ~2.39:1 |
| 16:9 HD | 36.0 | 20.25 | 16:9 |
Camera placement via Remote Control
# Set camera position
PUT http://localhost:8080/remote/object/property
{
"objectPath": "/Game/Maps/MainLevel.MainLevel:PersistentLevel.CineCameraActor_0",
"propertyName": "RelativeLocation",
"propertyValue": { "RelativeLocation": { "X": 500, "Y": -200, "Z": 180 } }
}
# Set focal length
PUT http://localhost:8080/remote/object/property
{
"objectPath": "/Game/Maps/MainLevel.MainLevel:PersistentLevel.CineCameraActor_0.CineCameraComponent",
"propertyName": "CurrentFocalLength",
"propertyValue": { "CurrentFocalLength": 50.0 }
}
# Set aperture
PUT http://localhost:8080/remote/object/property
{
"objectPath": "/Game/Maps/MainLevel.MainLevel:PersistentLevel.CineCameraActor_0.CineCameraComponent",
"propertyName": "CurrentAperture",
"propertyValue": { "CurrentAperture": 2.0 }
}
Camera placement via Python
import unreal
editor = unreal.EditorLevelLibrary()
# Spawn a cine camera
camera = editor.spawn_actor_from_class(
unreal.CineCameraActor,
unreal.Vector(500, -200, 180),
unreal.Rotator(0, 30, 0)
)
# Configure lens
cine_comp = camera.get_cine_camera_component()
cine_comp.set_editor_property("current_focal_length", 50.0)
cine_comp.set_editor_property("current_aperture", 2.0)
# Set focus to track an actor
focus_settings = cine_comp.get_editor_property("focus_settings")
focus_settings.focus_method = unreal.CameraFocusMethod.MANUAL
focus_settings.manual_focus_distance = 300.0
cine_comp.set_editor_property("focus_settings", focus_settings)
Cutscene workflow
Shot structure
A typical cutscene edit in Sequencer:
Master Sequence: MS_Cutscene_01
|-- LS_Shot_010 (establishing wide) [0.0s - 3.0s]
|-- LS_Shot_020 (character close-up) [3.0s - 5.5s]
|-- LS_Shot_030 (reaction shot) [5.5s - 7.0s]
|-- LS_Shot_040 (two-shot dialogue) [7.0s - 15.0s]
|-- LS_Shot_050 (action beat) [15.0s - 18.0s]
Shot numbering convention
- Number shots by 10s (010, 020, 030...) to leave room for inserts
- Insert shots: 015, 025, etc.
- Takes: append
_v01,_v02for iterations
Creating a shot list via Python
import unreal
# Create master sequence
asset_tools = unreal.AssetToolsHelpers.get_asset_tools()
factory = unreal.LevelSequenceFactoryNew()
master = asset_tools.create_asset(
"MS_Cutscene_01",
"/Game/Cinematics/Sequences",
unreal.LevelSequence,
factory
)
# Create individual shots
shot_names = ["LS_Shot_010", "LS_Shot_020", "LS_Shot_030"]
for name in shot_names:
shot = asset_tools.create_asset(
name,
"/Game/Cinematics/Sequences/Cutscene_01",
unreal.LevelSequence,
factory
)
Sequencer keyframing
Keyframe types
| Interpolation | Use case |
|---|---|
| Auto | Default -- smooth curves between keys |
| User | Manual tangent control |
| Break | Different in/out tangents |
| Linear | Constant-speed interpolation |
| Constant (Step) | Instant value change (no interpolation) |
Adding tracks and keyframes via Python
import unreal
# Get the sequence
sequence = unreal.load_asset("/Game/Cinematics/Sequences/LS_Shot_010")
movie_scene = sequence.get_movie_scene()
# Bind an actor (possessable)
# This must be done when the level with the actor is loaded
world = unreal.EditorLevelLibrary.get_editor_world()
actor = unreal.GameplayStatics.get_actor_of_class(world, unreal.CineCameraActor)
binding = sequence.add_possessable(actor)
# Add transform track
transform_track = binding.add_track(unreal.MovieScene3DTransformTrack)
transform_section = transform_track.add_section()
transform_section.set_start_frame(0)
transform_section.set_end_frame(150) # 5 seconds at 30fps
Cinematic lighting
Lighting for cinematics vs. gameplay
Cinematics often need:
- Three-point lighting per shot (key, fill, rim)
- Higher shadow quality (increase shadow resolution via console
r.Shadow.MaxCSMResolution 4096) - Rect Lights for soft, area-based illumination
- Light functions for patterns (gobos, window blinds)
- Animated light properties (intensity, color for mood shifts)
Animatable light properties
Keyframe these in Sequencer:
Intensity-- brightnessLightColor-- color temperature shiftsAttenuationRadius-- falloff distanceSourceRadius/SourceLength-- soft shadow spreadTemperature-- Kelvin color temperature (if using temperature mode)VolumetricScatteringIntensity-- god rays contribution
Audio and dialogue
Audio tracks in Sequencer
- Audio Track: Place audio assets directly on the timeline
- Subtitles: Use Dialogue Wave assets (contain subtitles + localization keys)
- Sync: Align audio waveform visually in Sequencer editor (enable waveform display)
Dialogue workflow
- Create
DialogueWaveassets for each line - Associate
DialogueVoice(per character) - Place DialogueWave on Sequencer Audio Track
- Keyframe character facial animations to match timing
- Use Anim Notifies for lip sync markers
Post-process animation
Keyframe post-processing for cinematic mood:
Common animated properties:
- Color Grading > Global Saturation (desaturate for flashbacks)
- Color Grading > Shadows/Midtones/Highlights Gain (color shifts)
- Depth of Field > Aperture (rack focus)
- Depth of Field > Focal Distance (focus pulls)
- Bloom > Intensity (dream sequences)
- Vignette > Intensity (tension, focus)
- Exposure > Compensation (brightness shifts)
- Film > Slope/Toe/Shoulder (look development)
Movie Render Queue (MRQ)
MRQ is the production renderer for final output.
MRQ settings
| Setting | Cinematic | Preview |
|---|---|---|
| Output Resolution | 3840x2160 (4K) | 1920x1080 |
| Anti-Aliasing | Temporal AA Samples: 64 | 8 |
| Spatial AA Samples | 4-8 | 1 |
| Output Format | EXR (16-bit) or PNG | JPEG |
| Motion Blur | Max quality | Default |
| Frame Rate | 24 (film) or 30 | 30 |
Render via Python
import unreal
# Get Movie Render Queue subsystem
mrq = unreal.MoviePipelineQueueSubsystem()
# Create a job
queue = mrq.get_queue()
job = queue.allocate_new_job(unreal.MoviePipelineExecutorJob)
job.sequence = unreal.SoftObjectPath("/Game/Cinematics/Sequences/MS_Cutscene_01")
job.map = unreal.SoftObjectPath("/Game/Maps/MainLevel")
# Configure output
config = job.get_configuration()
output_setting = config.find_or_add_setting_by_class(
unreal.MoviePipelineOutputSetting
)
output_setting.output_directory = unreal.DirectoryPath("{project}/Saved/MovieRenders/")
output_setting.file_name_format = "{sequence_name}/{shot_name}/{frame_number}"
output_setting.output_resolution = unreal.IntPoint(3840, 2160)
# Add image output
png_output = config.find_or_add_setting_by_class(
unreal.MoviePipelineImageSequenceOutput_PNG
)
# Render
executor = unreal.MoviePipelinePIEExecutor()
mrq.render_queue_with_executor(executor)
Console commands for rendering
# High quality rendering overrides
r.ScreenPercentage 200
r.Shadow.MaxCSMResolution 4096
r.Lumen.Reflections.MaxRoughnessToTrace 1.0
r.Lumen.TranslucencyVolume.Enable 1
r.VolumetricFog.GridSizeZ 128
Cinematic Blueprints
Triggering sequences from gameplay
// C++ -- Play a Level Sequence
UPROPERTY(EditAnywhere, Category = "Cinematic")
ULevelSequence* CutsceneSequence;
void AMyTrigger::PlayCutscene()
{
ALevelSequenceActor* SequenceActor = GetWorld()->SpawnActor<ALevelSequenceActor>();
SequenceActor->SetSequence(CutsceneSequence);
ULevelSequencePlayer* Player = SequenceActor->GetSequencePlayer();
Player->OnFinished.AddDynamic(this, &AMyTrigger::OnCutsceneFinished);
Player->Play();
// Disable player input during cutscene
APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
PC->SetCinematicMode(true, true, true, true, true);
}
void AMyTrigger::OnCutsceneFinished()
{
APlayerController* PC = UGameplayStatics::GetPlayerController(this, 0);
PC->SetCinematicMode(false, false, false, true, true);
}
Skip/pause functionality
ULevelSequencePlayer::Pause()/Play()for pauseULevelSequencePlayer::GoToEndAndStop()for skip- Bind skip to input action (typically a button press after a short hold)
Cinematography reference
Shot types
| Shot | Description | Focal length |
|---|---|---|
| Extreme Wide (EWS) | Full environment, tiny subject | 16-24mm |
| Wide (WS) | Full body in environment | 24-35mm |
| Medium (MS) | Waist up | 35-50mm |
| Medium Close-Up (MCU) | Chest up | 50-85mm |
| Close-Up (CU) | Face fills frame | 85-135mm |
| Extreme Close-Up (ECU) | Eyes or detail | 100-200mm |
| Over-the-Shoulder (OTS) | Dialogue framing | 50-85mm |
Camera movement types
| Move | Sequencer approach |
|---|---|
| Pan/Tilt | Keyframe camera rotation |
| Dolly | Keyframe camera position (forward/back) |
| Truck | Keyframe camera position (left/right) |
| Crane | Use Camera Rig Crane actor |
| Dolly track | Use Camera Rig Rail + spline |
| Handheld | Add procedural noise to transform curves |
| Orbit | Keyframe position around focal point |
Asset conventions
/Game/Cinematics/
Sequences/
MS_{SceneName}/ -- Master sequences
{SceneName}/
LS_Shot_{Number}.uasset -- Individual shots
Cameras/
BP_CineCam_{Name}.uasset -- Reusable camera rigs
Audio/
DW_{Character}_{Line}.uasset -- Dialogue Waves
DV_{Character}.uasset -- Dialogue Voice per character
Renders/
{SequenceName}/ -- MRQ output (not committed to source)
More from edhahn/agent-skills
software-architecture
>
8ue5-gamedev
>
6ue5-level-design
>
5game-designer
>
5multi-agent-chat
Coordination protocol for AI agents sharing a group chat channel (Discord, Slack, Teams, or any multi-user channel). Prevents infinite agent-to-agent loops, reduces noise, eliminates redundant responses, and establishes clear routing rules for who responds to what. Use this skill when you are an AI agent in a channel with other AI agents and human participants, when you see duplicate responses or echo loops between agents, when a human asks agents to coordinate better, when you need rules for when to speak vs. stay silent in a multi-agent channel, or when you want to reduce token waste from unnecessary agent chatter. Also applies to any shared workspace where multiple agents receive the same messages.
5ue5-character
>
5