Gum gum-tool-save-classes
Reference guide for Gum's save/load data model. Load this when working with GumProjectSave, ScreenSave, ComponentSave, StandardElementSave, ElementSave, StateSave, VariableSave, InstanceSave, BehaviorSave, or any serialization/deserialization of Gum project files.
git clone https://github.com/vchelaru/Gum
T=$(mktemp -d) && git clone --depth=1 https://github.com/vchelaru/Gum "$T" && mkdir -p ~/.claude/skills && cp -r "$T/.claude/skills/gum-tool-save-classes" ~/.claude/skills/vchelaru-gum-gum-tool-save-classes && rm -rf "$T"
.claude/skills/gum-tool-save-classes/SKILL.mdGum Save/Load Data Model Reference
Overview
Gum projects are serialized as XML files using .NET's
XmlSerializer. Each logical type has its own file extension: .gumx (project), .gusx (screen), .gucx (component), .gutx (standard element), .behx (behavior).
All save classes live in
GumDataTypes/.
Save Classes vs Runtime Classes
The Gum tool's core responsibility is editing and serializing save classes (the data model) to XML — it operates purely on save classes. Visualization (the wireframe preview) requires runtime classes and a Gum runtime; the tool uses KNI for this via the
EditorTabPlugin_XNA plugin, but other runtimes exist (MonoGame, FNA, Skia, Raylib). Gum.csproj should be save-class territory only. Runtime/rendering code that still lives there (e.g. WireframeObjectManager) is legacy being actively refactored out to plugins — do not add new runtime code to Gum.csproj.
Runtime usage: At runtime,
ElementSave/ScreenSave/ComponentSave are only present if the game loaded a Gum project (.gumx). Without a project, these classes are not used. However, StateSave, StateSaveCategory, and VariableSave are used at runtime regardless — they power the state system on GraphicalUiElement. For how save data is instantiated and applied at runtime (ToGraphicalUiElement, ApplyState, SetProperty), see the gum-property-assignment skill. For a deep dive into the full variable lifecycle from save data through runtime application and Forms state updates, see the gum-variable-deep-dive skill.
Class Relationships
GumProjectSave is the root. It stores only references to elements (screens, components, standards, behaviors) — not the element data itself. The actual element data lives in separate files and is loaded into [XmlIgnore] collections after deserialization. This is a deliberate two-phase loading pattern.
ElementSave is the abstract base for ScreenSave, ComponentSave, and StandardElementSave. All three are structurally identical — they differ only in subfolder and file extension. Each element owns a list of StateSave, StateSaveCategory, InstanceSave, and EventSave.
StateSave holds a list of VariableSave (and VariableListSave). A VariableSave stores a name/value pair. Variable names can be qualified with an instance name (e.g. "MyButton.X") or unqualified for element-level values (e.g. "Width").
BehaviorSave is independent of ElementSave but follows the same save/load pattern.
Important Concepts
Two-phase loading: The
.gumx file only records element references. After deserializing the project, a second pass loads each referenced element file from disk. Missing files are recorded in GumLoadResult rather than throwing — callers should check this object.
Qualified variable names: In
VariableSave.Name, a dot separates an instance name from a property name ("InstanceName.PropertyName"). VariableSave.SourceObject and VariableSave.RootName are computed helpers that split this. Element-level variables have no dot and SourceObject is null. EventSave.Name follows the same convention; use GetSourceObject() / GetRootName().
and the three variable states: A variable in a VariableSave.SetsValue
StateSave can be in one of three states:
- Not present — the
does not exist inVariableSave
. The property uses its inherited/default value.StateSave.Variables - Present with
— theSetsValue = false
exists but does not actively set a value. This state is required for exposed variables: when a component exposes an inner instance's property, the container's state must have aVariableSave
entry withVariableSave
so the exposed variable binding can resolve. Removing this variable would break the exposed variable chain. The edited icon does NOT show for these variables.SetsValue = false - Present with
— theSetsValue = true
actively sets its value. The edited icon shows in the tree view.VariableSave
When reverting a variable after failed validation, you must restore the exact previous state — not just the value. If the variable didn't exist before, remove it from the list. If it existed with
SetsValue = false, restore that. If it had a value, restore the value. Getting this wrong causes spurious undo entries or broken exposed variables.
Conditional serialization: Many properties on save classes are omitted from XML when they hold default values, using
ShouldSerializeXxx() methods. Don't assume a missing XML element means the property doesn't exist — it likely just holds its default value.
vs serialized: Runtime-only data (parent references, UI hints, event callbacks) is tagged [XmlIgnore]
[XmlIgnore] and never written to disk. Only the structural/data properties are serialized.
States and categories: An element has both a flat
States list (uncategorized) and a Categories list of StateSaveCategory, each of which has its own States list. AllStates (on ElementSave) enumerates both. The first uncategorized state is conventionally named "Default".
list: Cross-element variable binding is stored as a VariableReferences
VariableListSave<string> whose Name is "VariableReferences" or "InstanceName.VariableReferences". Each string entry is "LeftSide = RightSide" where the right side is a qualified path like "Components/MyComp.InstanceName.Width". An optional state prefix can appear before a colon: "Highlighted:Components/MyComp.InstanceName.Width". Rename logic must update both sides.
reference lists vs. loaded lists: The GumProjectSave
.gumx file serializes ScreenReferences, ComponentReferences, StandardElementReferences, BehaviorReferences (each a List<ElementReference> or List<BehaviorReference>). The [XmlIgnore] properties Screens, Components, StandardElements, Behaviors hold the loaded objects. Both must be updated on rename: the reference list (for .gumx) and the live objects (for in-memory state). AllElements is a computed [XmlIgnore] property that enumerates Screens + Components + Standards.
Clone methods: All save classes have a
Clone() method that produces a deep copy via FileManager.CloneSaveObject. Cloned instances have different object references than the originals — relevant when cross-referencing with live editor state.
BehaviorSave Structure
BehaviorSave is referenced from ElementSave.Behaviors (List<ElementBehaviorReference>). ElementBehaviorReference.BehaviorName is the plain string name that must be updated on behavior rename.
Key fields on
BehaviorSave:
— a singleRequiredVariables
listing variables that implementing components must exposeStateSave
—Categories
, each with its ownList<StateSaveCategory>
;States
enumerates themAllStates
—RequiredInstances
(instances the component must contain)List<BehaviorInstanceSave>
—RequiredAnimations
animation names the component must implementList<string>
Rename Cross-Reference Map
When any object is renamed, scan these fields across all elements:
| Renamed Object | Fields to Update | Where to Scan |
|---|---|---|
| Screen / Component / StandardElement | , , where , VariableReferences right-hand side | All Screens + Components |
| Instance (within an element) | (SourceObject prefix), (SourceObject prefix), where , where (value after the dot), VariableReferences left and right sides | Containing element + inheriting elements + elements referencing the container |
| State | where in elements that use the element as an instance | Elements referencing the owner element |
| StateSaveCategory | == old category name, root (e.g. ) | All Screens + Components |
| Exposed variable / VariableSave root name | , root in inheriting elements and instances, VariableReferences left and right sides | All elements |
| BehaviorSave | in , in | All Screens + Components (for ElementBehaviorReference); GumProjectSave (for BehaviorReferences) |
Note:
GetReferencesToElement in ReferenceFinder only scans Screens and Components — it does not scan StandardElements. If a standard element inherits from another standard element and the base is renamed, that reference won't be found.
Note: Behavior rename is not yet implemented in
ReferenceFinder. The method GetReferencesToBehavior does not exist; ElementBehaviorReference.BehaviorName will become stale on behavior rename.
File Locations
| Class | File |
|---|---|
| |
(abstract) | |
, , | (one file each) |
, | |
, | |
| |
| |
| |
, , | |
| |
| |