Gum gum-tool-codegen
Reference guide for the Gum tool's C# code generation system. Load this when working on CodeGenerator, CodeOutputPlugin, generated code structure, .codsj settings, OutputLibrary selection, Forms codegen, state generation, or the tool-side code generation pipeline. For CLI/headless codegen, see the gum-cli skill instead.
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-codegen" ~/.claude/skills/vchelaru-gum-gum-tool-codegen && rm -rf "$T"
.claude/skills/gum-tool-codegen/SKILL.mdGum Tool Code Generation System
What It Is
The code generation system produces C# partial classes from Gum Screens and Components. Two files per element:
.Generated.cs (auto-regenerated, never hand-edit) and .cs (user-editable stub with partial void CustomInitialize() hook). StandardElements are never generated.
MonoGameForms is the recommended default OutputLibrary for new projects. Non-forms (plain MonoGame) exists for legacy and specialized scenarios.
Architecture
Tool UI Shared Engine CodeOutputPlugin/ Gum.ProjectServices/CodeGeneration/ MainCodeOutputPlugin CodeGenerator (~5700 lines) CodeGenerationService CustomCodeGenerator CodeWindow (Code tab) CodeGenerationFileLocationsService ParentSetLogic CodeGenerationNameVerifier RenameService VariableExclusionLogic CodeOutputProjectSettingsManager CodeOutputElementSettingsManager
CodeGenerationService (tool-side) orchestrates generation by calling into CodeGenerator (shared engine). The same CodeGenerator is used by the CLI via HeadlessCodeGenerationService -- see the gum-cli skill for that path.
Configuration (.codsj files)
Project-level:
ProjectCodeSettings.codsj alongside the .gumx. Managed by CodeOutputProjectSettingsManager. Key settings: OutputLibrary, CodeProjectRoot, RootNamespace, ObjectInstantiationType, InheritanceLocation, AppendFolderToNamespace.
Element-level:
ElementName.codsj alongside the .gucx/.gusx. Managed by CodeOutputElementSettingsManager. Key settings: GenerationBehavior, namespace override, custom output path.
Key Enums
| Enum | Values | Notes |
|---|---|---|
| XamarinForms(0), WPF(1), Skia(2), Maui(3), MonoGame(4), MonoGameForms(5) | MonoGameForms is recommended default |
| FullyInCode, FindByName | FullyInCode generates all creation; FindByName wires references to externally-created instances |
| InGeneratedCode, InCustomCode | Controls which partial class file declares the base class |
| Gum, XamarinForms | Internal enum; Gum for MonoGame/MonoGameForms/Skia/raylib, XamarinForms for Xamarin/MAUI |
| NeverGenerate, GenerateManually, GenerateAutomaticallyOnPropertyChange | Per-element setting |
Generated Code Structure (in order)
- Using statements (auto-detected from instances)
- Namespace (root + optional folder path)
- Partial class with optional inheritance
- State enums (one per category)
- State properties with
callsApplyState() - Instance fields
- Custom variables (user-defined properties)
- Exposed variables (delegate to child instances)
- Constructor chain:
thenInitializeInstances()
thenAddToParents()ApplyDefaultVariables()
methodsApplyState()
(if enabled)ApplyLocalization()partial void CustomInitialize()
Non-Obvious Behavior
MonoGameForms
wrapping -- When OutputLibrary is MonoGameForms, property access on instances goes through .Visual
.Visual (e.g., this.Visual for root, this.InstanceName.Visual for children). The generated code treats everything that is not a StandardElement as a Forms object.
Forms base type from behaviors -- MonoGameForms determines the generated base class by scanning the element's behaviors (e.g., ButtonBehavior maps to Button). The method
GetGumFormsTypeFromBehaviors drives this.
Screen inheritance resolution order --
CodeGenerator.GetInheritance for ScreenSave resolves inheritance in this priority: element.BaseType > projectSettings.DefaultScreenBase > library-appropriate fallback (FrameworkElement for MonoGameForms, GraphicalUiElement otherwise). DefaultScreenBase defaults to empty string so users can switch OutputLibrary without stale base classes bleeding through.
State generation suppressed for Forms standards -- When OutputLibrary is MonoGameForms and the state container is a
StandardElementSave, state code is not generated; the Forms framework handles it.
Missing dependency auto-generation -- When generating for an element, the system checks if referenced elements lack code files and offers to generate them too. In auto-generation mode this happens silently.
ObjectFinder cache -- Code generation enables/disables
ObjectFinder.Self cache around generation loops for performance. Must be managed at the call site (not inside CodeGenerator).
VariableExclusionLogic -- Certain variables are excluded depending on OutputLibrary (e.g., Alpha excluded for XamarinForms). The plugin hooks into the
VariableExcluded query event to apply this.
Tool plugin auto-regeneration --
MainCodeOutputPlugin listens to nearly every edit event (variable set, instance add/delete, state changes, etc.) and auto-regenerates if the element's GenerationBehavior is GenerateAutomaticallyOnPropertyChange.
RequestCodeGenerationMessage -- External systems (like FlatRedBall editor integration) can trigger codegen via this CommunityToolkit.Mvvm message.
C# name compliance --
CodeGenerationNameVerifier prefixes C# keywords with @, leading digits with _, and replaces spaces with _.
RenameService -- When elements are renamed in the tool, updates generated code file names and internal references.
Key Files
| File | Purpose |
|---|---|
| Core codegen engine (~5700 lines) |
| User-editable partial class stub |
| Project settings classes + enums |
| Element settings class |
| Output path resolution |
| C# name compliance |
| Platform-specific variable exclusion |
| Tool UI plugin entry point |
| Tool-side generation orchestration |
| Forms parent relationship handling |
| Element rename to code rename |