Cinematic Shot Flows
The experimental UAgenticShotFlow asset — roles, segments, curves, movement models, corrections and playback in Agentic Gameplay Camera
Cinematic Shot Flows
Experimental. The cinematic half of this plugin — UAgenticShotFlow assets, the Sequencer flow track, the Stage rehearsal room and the editor toolsets — is Experimental in this release. Its API and asset formats may change between versions. The gameplay camera is the Beta half and does not depend on any of this.
A shot flow is authored coverage that is subject-agnostic: it names roles rather than actors, so one flow performs for any cast, anywhere. Everything that plays authored camera work — a runtime call, a Sequencer section, the editor Stage — reads the same asset and drives the same flow cursor, so what you approve in rehearsal is what plays in the game.
There is no DataTable and no JSON import for flows. Discovery is tag → asset: FlowTag is registry-searchable, so the camera registry finds the asset from the Asset Registry with nothing to configure.
Two flows ship with the plugin, under /AgenticGameplayCamera/Cinematic/Flows/:
| Asset | Tag | What it is |
|---|---|---|
SF_Dialogue_ShotReverse | Agentic.Cinematic.Flow.Dialogue.ShotReverse | Shot/reverse-shot coverage for two characters 2–5 m apart. Roles A and B, both required, head as the default bone. Establishing full shot at 35 mm, then two mirrored over-the-shoulder mediums at 50 mm that cut between each other and hold until a line-done signal. |
SF_Combat_Execution | Agentic.Cinematic.Flow.Combat.Execution | Two beats: the blow, then the landing. Roles Attacker and Victim. A 40 mm low medium, then a 0.7 s 85 mm close-up on the victim. Interrupt policy Sacred — a scripted kill gameplay can interrupt is not a scripted kill. |
The Asset
| Field | Meaning |
|---|---|
FlowTag | Agentic.Cinematic.Flow.<Family>.<Name>. The word a caller uses. Registry-searchable. |
Description | One line for the catalog. |
UsageHint | The staging the flow assumes — "two characters 3–8 m apart". |
Roles | What must be bound at play time. |
Segments | The timeline, in order. |
Policy | End conditions, interruption, corrections, inserts. |
RehearsalThumbnailPath | A file path written by the Stage's publish step, not a texture reference. |
The asset's own Validate is structural only — a valid tag, at least one segment, every subject role declared, no duplicate role names — and that is what the editor's data validation reports. Whether the film grammar is any good is a separate judgement, made by the evaluator against a rehearsal.
Roles
| Field | Notes |
|---|---|
Name | Referenced by a segment's subjects and by Weight.<Role> curves. |
Kind | Character (skeletal, bones meaningful), PointOfInterest (a landmark), Path (a camera path spline actor). |
DefaultBone | Aim socket for subjects that do not override it. Character only. |
bRequired | Playback refuses to start when a required role is unbound. |
DefaultSubjectTag | Auto-binds from the subsystem's subject registry when the caller binds nothing. |
Register subjects once and let the flows bind themselves:
Subsystem->RegisterSubject(SpeakerTag, SpeakingActor);
Subsystem->RegisterSubject(ListenerTag, ListeningActor);
Subsystem->PlayShotFlowByTag(DialogueFlowTag, FAgenticFlowBindings());Segments
A segment says when a shot starts, how it arrives, when it ends, and which of its values animate.
| Field | Notes |
|---|---|
Name | Label. |
Shot | The shot itself: subjects, placement, framing, lens, intent. |
EndOn | How the segment ends — see below. |
TransitionIn | The blend runs at the start of the incoming segment. |
Curves | Named curves over segment-local 0..1. |
Pin | Optional world-space pose override. |
A new segment starts out physical and composed: a 35 mm focal length, dolly-only group adjustment, head-room on, and a little lead room. So a flow shot moves the camera to its framing rather than zooming to it.
Ending a Segment
| Mode | Behavior |
|---|---|
Duration | Ends after Duration seconds. |
Signal | Holds until its signal tag is raised. |
External | Holds until the orchestrator calls continue. |
For Signal and External, Duration is only the estimate used for seeking, duration reporting and the Sequencer projection. It is never a timeout — a held segment holds.
A Duration segment's overshoot carries into the next segment, so boundaries never round up to a frame.
Transitions
Cut or Blend, with a time and a curve (the same curve vocabulary as the gameplay side: linear, ease in/out, overshoot, bounce, snap, anticipation, smoothstep, elastic, expo-out…). A cut has zero duration by definition.
Pins
A pin replaces the framing solve for its segment: placement, movement model, smoothing and the collision probe all stand down and the authored poses are honored exactly. Corrections still run. Key times are segment-local seconds, not normalized — a signal-held segment has no known length, so clamping at the last key is the honest answer.
A pin is world-space and therefore level-bound. Curves port to any cast in any set; a pin does not.
Shot Size
Two fields can name a shot's size, and they are not the same thing:
Framing.Sizeis the control the distance solve reads: aim at this band.Intent.SizeStartis the assertion the contract checks: this shot is a close-up.
Explicit control always wins; an undeclared control falls back to the intent, so a shot that only asserts its size is still aimed at that band. A genuine disagreement — both declared and different — is reported as a warning rather than silently resolved.
Bands are frame height in centimetres at the subject's depth. They are contiguous and total, and a boundary belongs to the tighter size.
| Size | Band (cm) | Automatic head-room |
|---|---|---|
ExtremeCloseUp | 0 – 35 | −0.15 |
CloseUp | 35 – 75 | 0.08 |
MediumShot | 75 – 190 | 0.12 |
FullShot | 190 – 320 | 0.15 |
LongShot | 320 – 100000 | 0.20 |
Unspecified | frame-fill fit | 0.10 |
The solve aims at a band's geometric centre so the result classifies back to the same size. When a pose is unachievable, a fixed degrade ladder runs — loosen the size one band, swap the orbit side, raise the height — and every step it took is recorded rather than hidden.
Curves
The curve vocabulary is fixed and closed; an unknown name is rejected, not ignored. Every curve is relative to the pair frame — origin at the weighted group centre, x along the line of action, z up — so the same move plays for any two actors anywhere. A present curve overrides the shot's static value for that segment; an absent one leaves it alone. Curves run first, so a movement model composes on top of them.
| Curve | Unit | Writes |
|---|---|---|
Weight.<Role> | 0..1 | That subject's framing weight |
Height | cm above group centre | Placement height |
Distance | scale on the solved distance (1 = as solved) | Placement distance scale |
Orbit | degrees in the orbit reference frame | Placement orbit |
Roll | degrees | Placement roll |
FocalLength | mm | Lens focal length |
Aperture | f-stop | Lens aperture |
FrameFill | fraction of frame height | Frame fill (size Unspecified only) |
PathAlpha | 0..1 along a Path role's spline | Consumed by the Path model only |
Movement Models
A shot holds one primary model and any number of layers. A model is a pure function of segment-local time and never touches the world: where a move needs level content it publishes a request naming roles, and the world-aware caller fulfils it.
| Model | Slot | Needs | Effect |
|---|---|---|---|
Static | primary | — | Holds the pose solved at segment start. |
Track | primary | — | Follows with a dead zone (8 cm by default), smoothed by the shot's own smoothing. |
Orbit | primary | — | Degrees per second on the orbit — a rate, not a sweep. |
PushIn | primary | — | Distance scale 1 → an end scale over a curve. The lens never moves. |
DollyZoom | primary | — | Focal length to an end value with distance scaled by the focal ratio. No-op on a non-physical lens. |
Path | primary | a Path role, and a look-at role that is a subject | Rail travel with manual progress along the spline. |
POIDrift | primary | a PointOfInterest role that is a subject | Drifts the pair-frame offset toward the point at a speed; the solve re-aims. |
RackFocus | layer | a from-role and a to-role, both subjects | Lens only. The pose is identical with and without it. |
Handheld | layer | — | Adds amplitude onto the shot's own shake; sets frequencies only where the shot declared none. |
A layer placed in the primary slot is rejected by the validator, not quietly ignored. The primary runs first, then each layer in author order.
There is deliberately no Crane model — a crane is the Height, Distance and Orbit curves on a segment.
Policy
| Field | Notes |
|---|---|
Inserts | Signal → flow pairs: reaction flows played over the top. |
Interrupt | See the table below. |
bLoop | Restart from the first segment at the end. |
EndAction | ReturnToPrevious, SwitchToMode, Hold or Custom. |
EndModeTag | The gameplay mode tag for SwitchToMode. |
BlendInTime / BlendOutTime | View-target blend onto and off the shot camera. Default 0.3 s. |
Corrections | Correction objects, run in priority order. |
Interruption
The policy is read from the flow currently playing, so an insert can declare its own answer.
| Policy | Result | What happens |
|---|---|---|
Sacred | Ignored | Nothing moves. Only an explicit segment skip gets through. |
Yield | Aborted | The flow ends as interrupted, the view blends back to the pawn, and the end action does not run. |
Resume | Suspended | The view blends back to the pawn and the cursor is kept — same segment, same elapsed time, same cast — until you resume it. |
ReactThenResume | Reacted | The signal is offered to the policy's inserts; the reaction plays over the top and the interrupted segment resumes itself. With no matching insert, the signal is ignored. |
Interrupting never releases a segment's signal hold, so raising a signal keeps its one meaning.
Corrections
Four correction classes ship, each declaring its own tag:
| Class | Tag |
|---|---|
| Collision | Agentic.Cinematic.Correction.Collision |
| Constraints | Agentic.Cinematic.Correction.Constraints |
| Dithering | Agentic.Cinematic.Correction.Dithering |
| Shake | Agentic.Cinematic.Correction.Shake |
Each has bEnabled and a Priority (lower runs earlier; 100 by default). A correction reports true only when it actually moved the camera, which is what makes the trace a record of what fired rather than a list of what was configured. This is the same source-agnostic pipeline the gameplay corrections use.
Occlusion is not a correction: a blocked pose goes through the degrade ladder and is reported as occluded frames on the trace.
Playback
Reach the subsystem with Get Cinematic Subsystem (from a player controller) or its world-context variant, then:
| Call | Purpose |
|---|---|
PlayShotFlow(Flow, Bindings) | Play an asset you already have. |
PlayShotFlowByTag(FlowTag, Bindings) | Resolve the tag through the registry and play it. |
StopShotFlow(bBlendOut) | Stop; the view blends back to the pawn over the policy's blend-out time. |
ContinueShotFlow() | Release an External segment — the orchestrator's "next". |
SkipShotFlowSegment() | Advance as if the segment had ended. Works while paused and while holding, and is the one input a Sacred flow still takes. |
SeekShotFlow(FlowTime) | Jump to an absolute flow time — what a Sequencer scrub calls every frame. |
RaiseCinematicSignal(SignalTag) | Release a Signal hold, or trigger an insert. |
InterruptShotFlow(Signal) | The gameplay seam; returns what the policy decided. |
ResumeShotFlow() | Continue a flow suspended by a Resume interruption. |
IsPlayingShotFlow() / IsShotFlowSuspended() | State queries. |
GetActiveShotFlow() / GetShotFlowBinding(Role) / GetShotFlowTime() | What is playing, who is bound, and where the cursor is. |
RegisterSubject / ClearSubject / ResolveSubject | The subject registry that feeds role auto-binding. |
All of these are Blueprint-callable.
The three doors — a direct call, a Sequencer flow section, and the editor Stage — drive one player, so behavior does not fork by entry point. When an external driver such as Sequencer owns the clock, it takes time control and advances the flow with its own frames.
Playback is deterministic: the same flow, the same tick deltas and the same signals produce the same events.
What the Trace Reports
One trace entry is opened per segment entry, so a looping flow records each pass. Every field is measured, never requested: the transition kind and time, when the segment was entered, how long it held, which side of the line the camera was on, the requested and solved size, how many degrade steps ran, whether the pose was still unachievable, the occluded / clipped / out-of-reach / solved frame counts, and which corrections fired.
A flow ends as Completed, Stopped, Replaced, Skipped or Interrupted, and the most recent completed trace stays readable afterwards.
Authoring and Rehearsal (Editor Only)
The Stage is a rehearsal room shipped as /AgenticGameplayCamera/Stage/L_Stage: it spawns stand-ins for a flow's roles, plays the authored sequence for real, and can capture a PNG sequence and a WAV of the session with measured frame intervals. Its settings live under Project Settings → Plugins → Agentic Camera Stage.
The Stage, the flow catalog and the authoring tools live in the Editor modules (AgenticCameraEditor and AgenticCameraToolsets), so they are absent from a packaged game entirely. Rehearsal is a development activity; only the runtime flow playback, which lives in the Runtime module, ships in your game.
With Epic's Experimental ToolsetRegistry plugin enabled, the same surfaces are exposed to an agent as toolsets: list the flows, describe one (its roles, per-segment shape, exposed curves, staging hint, and the schema the authoring calls accept), and export the whole catalog as JSON. The catalog is generated from the flow assets on every call and never stored, so it cannot drift from what would actually play. Export is one-way — nothing reads a flow back from JSON.
Without ToolsetRegistry, IsAvailable reports false and the toolsets are simply absent. The camera and the flows behave identically.
Sequencing flows into a scene — who speaks, what happens next, when a flow plays — is deliberately not in this plugin. A shot flow performs authored coverage against whoever is bound; deciding that beat 6 follows beat 5 belongs to your own narrative or quest system, which drives this camera by playing a flow tag.