Gum Tool Animations
State-based animation authoring in the editor: timeline animations that interpolate
between named States over time. NOT the same as runtime AnimationChains (see Landmines).
Where it lives
- Split like the editor tab (phase 80 of the Avalonia migration): the neutral
Tool/StateAnimationPlugin.Core (net10.0) holds StateAnimationPluginBase (all event wiring,
menu, tab, undo, delete option), the load/save and settings managers, the shared list hotkeys
(AnimationTabKeyHandler), and the timeline math (Timeline/TimelineLayout,
InterpolationCurve). Each head derives the exported plugin: WPF MainStateAnimationPlugin
(Gum/StateAnimationPlugin/, views Views/MainWindow.xaml, Timeline.xaml, StateView.xaml)
and Avalonia AvaloniaStateAnimationPlugin (Tool/Gum.Avalonia/Plugins/StateAnimation/, whose
TimelineView draws natively in Render). A behavior change to the tab belongs in the core, not
in either view. Tab is hidden until View ▸ View Animations.
- VMs (in Gum.Presentation):
ElementAnimationsViewModel → AnimationViewModel →
AnimatedKeyframeViewModel; the business logic is AnimationTabController.
Data model & serialization
- Persisted as a per-element
.ganx sidecar: <ElementName>Animations.ganx next to
the element's .gucx/.gusx (path: Managers/AnimationFilePathService.cs). NOT embedded
in the element file or .gumx. Load/save: Managers/AnimationCollectionViewModelManager.cs.
- Save classes live in
GumDataTypes/SaveClasses/*, namespace Gum.StateAnimation.SaveClasses.
ElementAnimationsSave → List<AnimationSave>; each AnimationSave holds three parallel
keyframe lists: state keyframes, sub-animation refs, named events.
- A state keyframe binds to a state by name string,
"Category/State" convention
(uncategorized = no slash). Resolution: AnimationViewModel.GetStateFromCategorizedName.
- Keyframes are cumulative — each combines with prior ones; preview rebuilds via
RefreshCumulativeStates.
Named events — FRB-only
"Add Named Event" authors a NamedEventSave (name + time). It round-trips to .ganx, but
Gum's own runtime never dispatches it — only FlatRedBall consumes named events. Skip in
non-FRB docs.
Runtime relationship (do NOT conflate)
- State animations (this skill) —
.ganx, interpolate between states. Runtime driver:
GumCommon/Runtime/AnimationController.cs + AnimationRuntime.cs (undocumented elsewhere).
- AnimationChains —
.achx, sprite-sheet flipbook on Sprite/NineSlice; see
[[gum-runtime-animation-chains]]. Different concept, different file, different runtime.
Landmines
- "Keyframe" is a union of 3 things.
AnimatedKeyframeViewModel is a state keyframe OR
sub-animation ref OR named event, discriminated by which string is non-empty (StateName →
state, else AnimationName → sub-anim, else event). No type enum; fans out into 3 lists on save.
- Misleading names on
AnimationSave. States = state keyframes (not element states);
Animations = sub-animation keyframes (not child animations).
- Interpolation types come from a NuGet package, not Gum.
InterpolationType/Easing
(state keyframes only) are FlatRedBall.Glue.StateInterpolation types from the standalone
FlatRedBall.InterpolationCore package — an easing/tweening library under the FlatRedBall
brand, NOT the FRB engine. The animation data model serializes these into .ganx.
- Sidecar must follow the element. Element rename/duplicate/delete must move the
.ganx;
wired via RenameManager/DuplicateService/ElementDeleteService in AssignEvents.
- Save is whitelist-filtered.
HandleDataChange only re-saves on specific property
changes; a new persisted keyframe field won't save unless added there.
Docs
User-facing content today is a 4-part tutorial under
docs/gum-tool/tutorials-and-examples/animation-tutorials/. Issue #480 wants a reference
section on the Animations tab itself (data model, named events, the tab UI), not tutorial-style.
1---2name: gum-tool-animations3description: Gum Tool Animations4---56# Gum Tool Animations78State-based animation authoring in the **editor**: timeline animations that interpolate9between named **States** over time. NOT the same as runtime AnimationChains (see Landmines).1011## Where it lives12- Split like the editor tab (phase 80 of the Avalonia migration): the neutral13 `Tool/StateAnimationPlugin.Core` (net10.0) holds `StateAnimationPluginBase` (all event wiring,14 menu, tab, undo, delete option), the load/save and settings managers, the shared list hotkeys15 (`AnimationTabKeyHandler`), and the timeline math (`Timeline/TimelineLayout`,16 `InterpolationCurve`). Each head derives the exported plugin: WPF `MainStateAnimationPlugin`17 (`Gum/StateAnimationPlugin/`, views `Views/MainWindow.xaml`, `Timeline.xaml`, `StateView.xaml`)18 and Avalonia `AvaloniaStateAnimationPlugin` (`Tool/Gum.Avalonia/Plugins/StateAnimation/`, whose19 `TimelineView` draws natively in `Render`). A behavior change to the tab belongs in the core, not20 in either view. Tab is hidden until View ▸ View Animations.21- VMs (in Gum.Presentation): `ElementAnimationsViewModel` → `AnimationViewModel` →22 `AnimatedKeyframeViewModel`; the business logic is `AnimationTabController`.2324## Data model & serialization25- Persisted as a **per-element `.ganx` sidecar**: `<ElementName>Animations.ganx` next to26 the element's `.gucx/.gusx` (path: `Managers/AnimationFilePathService.cs`). NOT embedded27 in the element file or `.gumx`. Load/save: `Managers/AnimationCollectionViewModelManager.cs`.28- Save classes live in `GumDataTypes/SaveClasses/*`, namespace `Gum.StateAnimation.SaveClasses`.29 `ElementAnimationsSave` → `List<AnimationSave>`; each `AnimationSave` holds **three parallel30 keyframe lists**: state keyframes, sub-animation refs, named events.31- A state keyframe binds to a state **by name string**, `"Category/State"` convention32 (uncategorized = no slash). Resolution: `AnimationViewModel.GetStateFromCategorizedName`.33- Keyframes are **cumulative** — each combines with prior ones; preview rebuilds via34 `RefreshCumulativeStates`.3536## Named events — FRB-only37"Add Named Event" authors a `NamedEventSave` (name + time). It round-trips to `.ganx`, but38**Gum's own runtime never dispatches it** — only FlatRedBall consumes named events. Skip in39non-FRB docs.4041## Runtime relationship (do NOT conflate)42- **State animations (this skill)** — `.ganx`, interpolate between states. Runtime driver:43 `GumCommon/Runtime/AnimationController.cs` + `AnimationRuntime.cs` (undocumented elsewhere).44- **AnimationChains** — `.achx`, sprite-sheet flipbook on Sprite/NineSlice; see45 [[gum-runtime-animation-chains]]. **Different concept, different file, different runtime.**4647## Landmines48- **"Keyframe" is a union of 3 things.** `AnimatedKeyframeViewModel` is a state keyframe OR49 sub-animation ref OR named event, discriminated by which string is non-empty (StateName →50 state, else AnimationName → sub-anim, else event). No type enum; fans out into 3 lists on save.51- **Misleading names on `AnimationSave`.** `States` = state *keyframes* (not element states);52 `Animations` = sub-animation *keyframes* (not child animations).53- **Interpolation types come from a NuGet package, not Gum.** `InterpolationType`/`Easing`54 (state keyframes only) are `FlatRedBall.Glue.StateInterpolation` types from the standalone55 **`FlatRedBall.InterpolationCore`** package — an easing/tweening library under the FlatRedBall56 brand, NOT the FRB engine. The animation data model serializes these into `.ganx`.57- **Sidecar must follow the element.** Element rename/duplicate/delete must move the `.ganx`;58 wired via RenameManager/DuplicateService/ElementDeleteService in `AssignEvents`.59- **Save is whitelist-filtered.** `HandleDataChange` only re-saves on specific property60 changes; a new persisted keyframe field won't save unless added there.6162## Docs63User-facing content today is a 4-part tutorial under64`docs/gum-tool/tutorials-and-examples/animation-tutorials/`. Issue #480 wants a *reference*65section on the Animations tab itself (data model, named events, the tab UI), not tutorial-style.