Overview
Morph targets (also called blend shapes or shape keys) are usually driven by curves baked into the animation or by gameplay code. MorphCue lets animators drive them right on the notify track of the animation editor, with no code and no curve authoring, and lets programmers drive the same morphs from Blueprint or C++.
- Morph Cue notify state: place it on a sequence, montage or composite; its length is the playback length.
- Layered morphs: one notify drives any number of morph targets, each with its own values and timing.
- Easing library: Linear, Sine, Quad, Cubic, Expo, Smooth Step, or your own Curve Float.
- Loops and windows: repeat a layer N times and play it over only part of the notify.
- Blend modes: Override, Additive or Multiply against the weight the morph had when the cue began.
- End actions: keep the final value, restore the previous value or reset to zero - also when the animation is interrupted.
- Morph presets: data assets of named weights (expressions, visemes, body shapes) played by a notify, the component or the library.
- Modular characters: also drive attached skeletal meshes or every mesh on the actor, filtered by component tag.
- Random variation: random end value and random delay on every play, so repeated blinks never look identical.
- Mirroring: swap
_L/_R(or any token pair) in morph names for mirrored animations. - Morph Cue Player component: play, blend, preset and stop morphs at runtime with a finished event.
- Searchable morph picker in the details panel, filled from the preview mesh, with free typing and unknown-name highlighting.
- Safe on many characters at once: every mesh running the same animation keeps its own cue state.
Requirements
| Requirement | Details |
|---|---|
| Unreal Engine | 4.27 and 5.8 |
| Modules | MorphCue (Runtime) and MorphCueEditor (Editor, details panel picker only) |
| Dependencies | None (engine modules only; no other plugins are enabled) |
| Mesh | Any skeletal mesh imported with morph targets |
| Platforms | Win64 and Mac (the modules list these platforms in the plugin descriptor). The code is platform-independent engine C++ with no OS-specific calls. |
| Network Replicated | No. Morph targets are cosmetic: notifies run on every machine that plays the animation. |
Installation
- Install MorphCue from Fab into your engine, or copy the
MorphCuefolder into your project'sPluginsfolder. - Enable MorphCue in Edit > Plugins and restart the editor.
- C++ only: add
PublicDependencyModuleNames.Add("MorphCue");to yourBuild.cs.
Quick start
- Open an animation sequence or montage of a mesh that has morph targets.
- Right-click a notify track and choose Add Notify State > Morph Cue. Drag its ends to the frames where the morph should play.
- Select the notify. In Layers, expand element 0 and click Pick next to Morph, then choose a morph target.
- Keep Playback on A to B to A, set End (B) to 1 and scrub or play: the morph rises and falls over the notify.
- Add more layers for more morphs, or set a Preset to play a whole expression.
Morph Cue: EyeBlink_L +1 (Mirrored).The Morph Cue notify
Notify State UMorphCueNotifyState — displayed as Morph Cue.
| Property | Default | Description |
|---|---|---|
| Layers | 1 empty layer | Morph targets played by this cue (see Layers). |
| Preset | None | Optional preset: each of its morphs plays from 0 to its preset weight. |
| Preset Weight | 1 | Scale applied to the preset weights. |
| Preset Playback / Preset Easing | A to B to A / Sine In Out | How the preset morphs are played. |
| End Action | Keep Final Value | What happens to the morphs when the notify ends or the animation is interrupted. |
| Time Source | Elapsed Time | Elapsed Time accumulates frame time. Animation Time reads the animation's own time, so it follows play rate and editor scrubbing (UE 5.8; UE 4.27 uses elapsed time). |
| Mesh Targets / Mesh Tag | This Mesh / None | Which meshes are driven (see Modular characters). |
| Mirror / Mirror Pairs | Off / _L-_R, _l-_r, Left-Right | Swap left/right tokens in every morph name (see Mirroring). |
Blueprint children of the notify can implement event On Cue Begin (mesh, total duration) and event On Cue End (mesh). pure Get Resolved Layers returns the layers that will play (preset expanded, names mirrored) and Get Active Instance Count the number of meshes running the cue.
Layers
struct FMorphCueLayer — one morph target over a window of the cue.
| Field | Default | Description |
|---|---|---|
| Morph | None | The morph target (picker, see Morph picker). |
| Playback | A to B to A | A holds the start value, A to B, B to A, A to B to A. |
| Start (A) / End (B) | 0 / 1 | The two weights. Values outside 0-1 are allowed (over-driven or negative shapes) and B may be lower than A. |
| Easing / Custom Curve | Linear / None | Easing of each playback segment; Custom Curve maps time 0-1 to alpha (0 = A, 1 = B). |
| Blend Mode | Override | See Blend modes. |
| Loops | 1 | How many times the playback repeats inside the window. |
| Window Start / Window End | 0 / 1 | Part of the notify the layer plays over, as fractions of its length. Before the window the layer holds its first value, after it the final value. |
| Random End Offset | 0 | Each play adds a random offset in [-X, X] to B. |
| Random Delay | 0 | Each play starts the layer later by a random fraction of its window, up to X (max 0.9). |
EyeBlink_L, A to B to A, Sine In Out, Window 0-0.4, Random Delay 0.2, Random End Offset 0.05; turn on Mirror and add a second notify for the right eye, or add a second layer EyeBlink_R.Playback, easing & loops
At each frame a layer computes its progress through its window (0 to 1), splits it into Loops cycles and turns each cycle into a shape between A (0) and B (1):
| Playback | Shape over one cycle | Final value |
|---|---|---|
| A | constant A | A |
| A to B | ease(t) | B |
| B to A | 1 - ease(t) | A |
| A to B to A | ease(2t) for the first half, ease(2 - 2t) for the second | A |
Easings: Linear, Sine In, Sine Out, Sine In Out, Quad In, Quad Out, Quad In Out, Cubic In Out, Expo In Out, Smooth Step and Custom Curve. When the notify ends, the layer is snapped to its exact final value (with Keep Final Value) even if the last frame stopped short of it.
Blend modes & end actions
When a cue begins, MorphCue reads the current weight of each of its morphs on each target mesh (the starting weight).
| Blend Mode | Weight written | Use it for |
|---|---|---|
| Override | played value | Most cues. |
| Additive | starting weight + played value | A bulge or wrinkle on top of a shape set by gameplay. |
| Multiply | starting weight × played value | Temporarily damping a shape (B = 0 fades it out). |
| End Action | Result when the notify ends |
|---|---|
| Keep Final Value | The final value of the playback stays on the mesh. |
| Restore Previous Value | Each morph gets back its starting weight. |
| Reset To Zero | Each morph is set to 0. |
Presets
Data Asset UMorphCuePreset — create one with Add > Miscellaneous > Data Asset > Morph Cue Preset.
| Property | Description |
|---|---|
| Values | Morph targets and their weights (for example Smile 1, CheekRaise 0.6, EyeSquint 0.3). |
| Preview Mesh | Editor only: the mesh whose morph targets the picker lists. |
Play a preset from a notify (Preset), from the component (Play Preset / Clear Preset) or instantly with Apply Preset. Get Value and Has Morph read a preset. Capture Morph Targets returns the current weights of a mesh, ready to store in a preset.
Modular characters
| Mesh Targets | Meshes driven |
|---|---|
| This Mesh | The mesh playing the animation. |
| This Mesh And Attached Meshes | That mesh plus every skeletal mesh attached below it (head, beard, clothes of a modular character). |
| All Meshes On Actor | Every skeletal mesh component of the owning actor. |
When Mesh Tag is set, the extra meshes must carry that component tag; the playing mesh is always included. Meshes without the morph simply ignore it.
Mirroring
With Mirror on, the first Mirror Pair found in each morph name is swapped: Brow_L becomes Brow_R and MouthRight becomes MouthLeft. Use it on a mirrored copy of an animation, or to reuse one notify setup for both sides. Matching is case-sensitive. Mirror Morph Name does the same in Blueprint.
Morph Cue Player component
Component UMorphCueComponent — displayed as Morph Cue Player. Add it to any actor with a skeletal mesh. It ticks only while something is playing.
| Node | Type | Description |
|---|---|---|
| Play Morph (Morph, From, To, Duration, Easing) | call | Plays a morph from one weight to another. |
| Blend Morph To (Morph, Target, Duration, Easing) | call | Blends from the current weight to Target. |
| Play Layer (Layer, Duration, End Action) | call | Plays a full layer: playback, loops, window, blend mode and variation. |
| Play Preset (Preset, Duration, Weight, Easing) | call | Blends every morph of the preset to its weight. |
| Clear Preset (Preset, Duration, Easing) | call | Blends every morph of the preset back to 0. |
| Stop Morph / Stop All (Restore) | call | Stops playback; Restore puts back the weights from before it started. |
| Is Morph Playing / Get Playing Count | pure | Playback state. |
| Set Target Mesh / Get Target Mesh | call | The mesh to drive. Default: Target Mesh Reference, else the owner's first skeletal mesh. |
| On Morph Finished (Morph) | event | Fires when a morph reaches the end of its duration (not when stopped). |
Properties: Target Mesh Reference (component picker), Mesh Targets and Mesh Tag (as on the notify). Playing a morph that is already playing replaces it and continues from its current weight.
Blueprint library
Function Library UMorphCueLibrary — category MorphCue.
| Node | Type | Description |
|---|---|---|
| Get Morph Target Names | pure | All morph target names of a mesh component. |
| Get Morph Target Names From Asset | pure | All morph target names of a skeletal mesh asset. |
| Set Morph Targets | call | Sets many weights at once, optionally on attached or sibling meshes. |
| Apply Preset | call | Applies a preset instantly, scaled by Weight. |
| Capture Morph Targets | call | Current weights of a mesh (non-zero only by default). |
| Reset Morph Targets | call | Clears all morph weights on the target meshes. |
| Evaluate Easing | pure | Any MorphCue easing at alpha 0-1. |
| Evaluate Layer | pure | The value a layer plays at a given time of a cue. |
| Mirror Morph Name | pure | Swaps a left/right token in a name. |
| Gather Target Meshes | call | The meshes a cue started on a mesh would drive. |
| To Morph Cue Name / To Name | pure | Automatic conversions between Name and Morph Cue Name. |
Morph picker
Every Morph field (FMorphCueName) is shown as a text box plus a Pick button. The list is searchable and is filled from:
- the preview mesh of the animation being edited (sequence, montage or composite), or its skeleton's preview mesh;
- a preset's Preview Mesh;
- the owning actor's skeletal mesh for components placed in a level.
You can always type a name. When a mesh is known, a name it does not have is shown in orange and the tooltip says so.
Debugging
Console variable MorphCue.Debug 1 prints every weight MorphCue writes on screen, tagged with its source (Notify, End, Player, Set), in development builds. It does nothing in shipping builds.
C++
#include "MorphCueComponent.h"
#include "MorphCueLibrary.h"
// Blink with the runtime player
if (UMorphCueComponent* Morphs = FindComponentByClass<UMorphCueComponent>())
{
FMorphCueLayer Blink;
Blink.Morph = FMorphCueName(TEXT("EyeBlink_L"));
Blink.Playback = EMorphCuePlayback::PingPong;
Blink.Easing = EMorphCueEasing::SineInOut;
Blink.RandomEndOffset = 0.05f;
Morphs->PlayLayer(Blink, 0.18f);
Morphs->PlayPreset(SmilePreset, 0.4f);
}
// Read and write weights directly
TArray<FMorphCueValue> Current = UMorphCueLibrary::CaptureMorphTargets(GetMesh());
UMorphCueLibrary::SetMorphTargets(GetMesh(), Current, EMorphCueMeshTargets::ThisAndAttached);
The evaluation helpers are available to C++ as FMorphCueMath (Ease, Shape, Evaluate, FinalValue, Blend, Mirror, WithVariation).
Troubleshooting
| Symptom | Cause and fix |
|---|---|
| Nothing moves | Check that the mesh really has the morph (the name turns orange when it does not) and that the notify is on a track of the animation that is playing. Try MorphCue.Debug 1. |
| The picker list is empty | The animation has no preview mesh: set one in the animation editor toolbar, or type the name. |
| The morph ends too early or late at a different play rate | Set Time Source to Animation Time (UE 5.8). |
| The morph stays on after the animation | That is Keep Final Value; use Restore Previous Value or Reset To Zero, or play A to B to A. |
| Clothes or heads of a modular character do not follow | Set Mesh Targets to This Mesh And Attached Meshes or All Meshes On Actor; the other meshes need morph targets with the same names. |
| An animation curve fights the morph | A morph target curve with the same name in the playing animation also writes that weight. Drive each morph from one place: remove the curve from the animation or use a different morph. |
Credits
© 2026 Alpha XP — alphaxp.net · Support: support@alphaxp.net. Built for Unreal Engine 4.27 and 5.8.