GS_Motion
Track-based animation and tween system — abstract base classes for motions, tracks, composites, assets, and proxies with a domain extension pattern.
GS_Motion is the framework’s central track-based animation system. It defines abstract base classes that domain gems extend with concrete track types — GS_UI extends it with 8 UI animation tracks (.uiam assets), and GS_Juice extends it with 2 feedback tracks (.feedbackmotion assets). The system handles playback timing, per-track easing, proxy-based entity targeting, and deep-copy runtime instancing from data assets.
For usage guides and setup examples, see The Basics: GS_Core.
Contents
Architecture
GS_MotionTrack (abstract base)
├── UiMotionTrack (GS_UI domain base)
│ ├── UiPositionTrack
│ ├── UiScaleTrack
│ ├── UiRotationTrack
│ ├── UiElementAlphaTrack
│ ├── UiImageAlphaTrack
│ ├── UiImageColorTrack
│ ├── UiTextColorTrack
│ └── UiTextSizeTrack
└── FeedbackMotionTrack (GS_Juice domain base)
├── FeedbackTransformTrack
└── FeedbackMaterialTrack
GS_MotionAsset (abstract base)
├── UiAnimationMotionAsset (.uiam)
└── FeedbackMotionAsset (.feedbackmotion)
GS_MotionComposite (runtime instance)
└── Created by asset's CreateRuntimeComposite()
Core Classes
| Class | Description | Page |
|---|
| GS_MotionTrack | Abstract base for all animation tracks — fields, lifecycle, virtual methods, extension guide. | MotionTrack |
| GS_Motion | Playback engine — ticks tracks, computes per-track progress windows, applies easing, manages lifecycle. | Motion Engine |
| GS_MotionComposite | Runtime deep-copy instance with proxy entity overrides — created from GS_MotionAsset. | MotionComposite |
| GS_MotionAsset | Abstract base for motion data assets — holds track definitions and creates runtime composites. | MotionAsset |
| GS_MotionProxy | Serialized struct for track-to-entity redirection — allows designers to target named tracks at different entities. | MotionProxy |
Domain Extensions
GS_Motion is designed to be extended by domain gems. Each domain creates its own track hierarchy, asset type, and file extension.
| Domain | Gem | Base Track | Concrete Tracks | Asset Extension |
|---|
| UI Animation | GS_UI | UiMotionTrack | Position, Scale, Rotation, ElementAlpha, ImageAlpha, ImageColor, TextColor, TextSize (8) | .uiam |
| Feedback | GS_Juice | FeedbackMotionTrack | FeedbackTransformTrack, FeedbackMaterialTrack (2) | .feedbackmotion |
Extension Pattern
To create a new motion domain:
- Create a domain base track —
class MyTrack : public GS_Core::GS_MotionTrack - Create concrete tracks extending the domain base — each overrides
Update(float easedProgress) and GetTypeName() - Create a domain asset —
class MyAsset : public GS_Core::GS_MotionAsset with vector<MyTrack*> m_tracks - Create an instance wrapper struct (not a component) — holds
Asset<MyAsset> + vector<GS_MotionProxy>, manages Initialize / Unload / Play / Stop - Embed the wrapper — components embed the instance wrapper struct as a serialized field
Critical: All track vectors must use raw pointers: vector<MyTrack*>. Never use unique_ptr — O3DE SerializeContext requires raw pointers for polymorphic enumeration in the asset editor.
See Also
For conceptual overviews and usage guides:
For class references:
For domain extensions:
Get GS_Core
GS_Core — Explore this gem on the product page and add it to your project.
1 - GS_MotionTrack
Abstract base class for all animation tracks — fields, lifecycle, and virtual methods for domain extension.
GS_MotionTrack is the abstract base class for all animation tracks in the GS_Motion system. Each track animates one aspect of an entity over a time window within a motion. Domain gems extend this with concrete track types — GS_UI provides 8 LyShine tracks, GS_Juice provides 2 feedback tracks.
For usage guides and setup examples, see The Basics: GS_Core.
Fields
| Field | Type | Description |
|---|
| m_id | AZ::Uuid | Unique track identifier (auto-generated). |
| m_identifier | AZStd::string | Proxy label — if set, the track appears in the proxy list for entity override targeting. |
| curveType | CurveType | Easing curve applied to track progress (from the Curves utility library). |
| startTime | float | Time offset before the track begins playing (seconds). |
| duration | float | Track playback duration (seconds). |
| startVarianceMin | float | Minimum random variance added to start time. |
| startVarianceMax | float | Maximum random variance added to start time. |
Lifecycle
Each track goes through a fixed lifecycle managed by the parent GS_Motion:
| Phase | Method | Description |
|---|
| Initialize | Init(AZ::EntityId owner) | Stores the owner entity. Called once when the motion is initialized. |
| Start | Start() | Called when the track’s time window begins. |
| Update | Update(float easedProgress) | Called each frame with eased progress (0 → 1). Override this in concrete tracks. |
| End | End() | Called when the track’s time window completes. |
| Unload | Unload() | Cleanup. Called when the motion is unloaded. |
Virtual Methods
These methods must be overridden in concrete track implementations:
| Method | Returns | Description |
|---|
Update(float easedProgress) | void | Apply the animation at the given eased progress value (0 → 1). |
GetTypeName() | AZStd::string | Return the track’s display name for proxy labels in the editor. |
Extension Guide
To create a new domain of animation tracks:
- Create a domain base track:
class MyTrack : public GS_Core::GS_MotionTrack — this serves as the common base for all tracks in your domain. - Create concrete tracks extending the domain base — each overrides
Update(float easedProgress) to animate a specific property. - Reflect the track class using O3DE’s
SerializeContext and EditContext. The system discovers the new type automatically.
Critical: Track vectors must use raw pointers (vector<MyTrack*>). Never use unique_ptr — O3DE SerializeContext requires raw pointers for polymorphic enumeration in the asset editor.
See Also
Get GS_Core
GS_Core — Explore this gem on the product page and add it to your project.
2 - GS_Motion
The playback engine — ticks through tracks, computes per-track progress windows, and manages motion lifecycle.
GS_Motion is the playback engine that drives animation tracks. It ticks through all tracks each frame, computes per-track progress windows based on start time and duration, applies easing curves, and calls Update(easedProgress) on each active track. It handles motion lifecycle from initialization through completion.
For usage guides and setup examples, see The Basics: GS_Core.
API Reference
| Method | Parameters | Returns | Description |
|---|
Play | — | void | Begin playback from the start. |
PlayWithCallback | AZStd::function<void()> cb | void | Play and invoke callback on completion. |
Stop | — | void | Stop playback immediately. |
Initialize | AZ::EntityId owner | void | Initialize all tracks with the owner entity. |
Unload | — | void | Unload all tracks and clean up. |
Fields
| Field | Type | Description |
|---|
| motionName | AZStd::string | Display name for the motion. |
| tracks | vector<GS_MotionTrack*> | The tracks in this motion. |
| loop | bool | Whether playback loops. |
| onComplete | function<void()> | Completion callback (set via PlayWithCallback). |
How It Works
Each frame during playback:
- The motion calculates the global elapsed time.
- For each track, it computes the track-local progress based on
startTime and duration. - If the track is within its active window, the progress is eased using the track’s
curveType. Update(easedProgress) is called on the track with the eased value (0 → 1).- When all tracks complete,
OnMotionComplete() is called.
Virtual Methods
| Method | Description |
|---|
OnMotionComplete | Called when playback finishes. Override in subclasses for custom teardown. |
See Also
Get GS_Core
GS_Core — Explore this gem on the product page and add it to your project.
3 - GS_MotionComposite
Runtime deep-copy motion instance with proxy entity overrides — created from GS_MotionAsset for per-entity playback.
GS_MotionComposite is the runtime instance of a motion, created from a GS_MotionAsset. It deep-copies all tracks so each entity gets independent playback state, and applies proxy overrides to redirect specific tracks to different entities in the hierarchy.
For usage guides and setup examples, see The Basics: GS_Core.
GS_MotionComposite extends GS_Motion. When an asset’s CreateRuntimeComposite() is called, all tracks are SC-cloned (serialization-context cloned) into a new composite instance. This ensures each entity playing the same motion has its own independent track state — no shared mutation.
API Reference
| Method | Parameters | Returns | Description |
|---|
ApplyProxies | AZ::EntityId owner, vector<GS_MotionProxy> proxies | void | Matches proxy trackIds to tracks and overrides the target entity for each matched track. |
How It Works
- Creation:
GS_MotionAsset::CreateRuntimeComposite() deep-copies all asset tracks into a new composite. - Proxy Application:
ApplyProxies() walks the proxy list, matching each proxy’s m_trackId to a track’s m_id. Matched tracks redirect their owner entity to the proxy’s m_proxyEntity. - Playback: The composite plays exactly like a regular GS_Motion — it ticks tracks, applies easing, and calls
Update(). - Cleanup: On
Unload(), the composite cleans up all deep-copied tracks.
See Also
Get GS_Core
GS_Core — Explore this gem on the product page and add it to your project.
4 - GS_MotionAsset
Abstract base for motion data assets — holds track definitions and creates runtime composites.
GS_MotionAsset is the abstract base class for motion data assets. Domain gems extend this with their own asset type and file extension — GS_UI creates UiAnimationMotionAsset (.uiam), GS_Juice creates FeedbackMotionAsset (.feedbackmotion). Assets are created and edited in the O3DE Asset Editor.
Extends AZ::Data::AssetData. All subclasses require GS_AssetReflectionIncludes.h in their header — see Serialization Helpers.
For usage guides and setup examples, see The Basics: GS_Core.
API Reference
| Method | Returns | Description |
|---|
GetTrackInfos | vector<GS_TrackInfo> | Returns track UUID + label pairs for proxy list synchronization in the editor. |
CreateRuntimeComposite | GS_MotionComposite* | Factory — deep-copies all asset tracks into a new runtime GS_MotionComposite instance. |
GS_TrackInfo
Lightweight struct used for proxy synchronization between asset tracks and instance proxy lists.
| Field | Type | Description |
|---|
| id | AZ::Uuid | Track identifier (matches the track’s m_id). |
| label | AZStd::string | Track display name (from GetTypeName()). |
Domain Extensions
| Domain | Gem | Asset Class | Extension | Tracks |
|---|
| UI Animation | GS_UI | UiAnimationMotionAsset | .uiam | 8 LyShine-specific tracks |
| Feedback | GS_Juice | FeedbackMotionAsset | .feedbackmotion | 2 feedback tracks |
Extension Guide
To create a new domain asset type:
- Create
class MyAsset : public GS_Core::GS_MotionAsset with vector<MyDomainTrack*> m_tracks. Include GS_AssetReflectionIncludes.h in your asset’s header — see Serialization Helpers. - Implement
GetTrackInfos() — iterate tracks and return UUID + label pairs. - Implement
CreateRuntimeComposite() — deep-copy tracks into a new GS_MotionComposite. - Register the asset type in your gem’s
DataAssetsSystemComponent. - Add a
.setreg entry for the asset processor to recognize your file extension.
Critical: Track vectors must use raw pointers (vector<MyTrack*>). O3DE SerializeContext requires raw pointers for polymorphic enumeration.
See Also
Get GS_Core
GS_Core — Explore this gem on the product page and add it to your project.
5 - GS_MotionProxy
Serialized struct for track-to-entity redirection — allows designers to target named tracks at different entities.
GS_MotionProxy is a serialized struct that allows designers to redirect a named track to a different entity in the hierarchy. This enables a single motion asset to animate multiple entities — for example, a UI animation that moves one element while fading another.
For usage guides and setup examples, see The Basics: GS_Core.
Fields
| Field | Type | Description |
|---|
| m_trackId | AZ::Uuid | References the track’s m_id. Matched during ApplyProxies(). |
| m_label | AZStd::string | Read-only display label (synced from track info at edit time via GetTrackInfos()). |
| m_proxyEntity | AZ::EntityId | The entity this track should target instead of the motion’s owner entity. |
How It Works
- Edit time: The proxy list syncs from the asset’s track info. Each track with an
m_identifier (non-empty label) appears as a proxy slot in the inspector. - Designer assignment: The designer drags an entity reference into the proxy’s
m_proxyEntity field. - Runtime: When
GS_MotionComposite::ApplyProxies() runs, it matches each proxy’s m_trackId to a track’s m_id and overrides that track’s target entity. - Playback: The track now animates the proxy entity instead of the motion’s owner.
Usage
Proxies are embedded in instance wrapper structs (e.g., UiAnimationMotion, FeedbackMotion) alongside the asset reference. Components serialize the proxy list, and the wrapper handles synchronization with the asset.
Only tracks with a non-empty m_identifier appear in the proxy list. Tracks without an identifier always animate the owner entity.
See Also
Get GS_Core
GS_Core — Explore this gem on the product page and add it to your project.