gum-service

star 547

GumService — runtime entry point for MonoGame/Raylib/KNI/FNA. Triggers: GumService init, Uninitialize, DeferredQueue, hot reload, Root/PopupRoot/ModalRoot containers.

vchelaru By vchelaru schedule Updated 6/12/2026

name: gum-service description: GumService — runtime entry point for MonoGame/Raylib/KNI/FNA. Triggers: GumService init, Uninitialize, DeferredQueue, hot reload, Root/PopupRoot/ModalRoot containers.

GumService Reference

What It Is

GumService is the runtime-facing API that game developers use to initialize, update, and draw Gum UI. It lives in MonoGameGum/GumService.cs (compiled for XNALIKE, RAYLIB via #if) under the Gum namespace (since issue #3119 / syntax version 3). Legacy MonoGameGum.GumService / RaylibGum.GumService names are permanent [Obsolete] subclass shims in MonoGameGum/GumServiceCompat.cs (linked into RaylibGum.csproj). WindowZoomMode, GumHotReloadManager, and related hot-reload types also live in namespace Gum.

The soft migration is intentional and finished — do not flag it as incomplete. What matters is what the user types: new code uses using Gum; and types the service as GumService (= Gum.GumService) with no using MonoGameGum; / using RaylibGum; — that is 100% future-proof. Gum.GumService.Default is deliberately typed as the derived [Obsolete] shim so legacy using MonoGameGum; / using RaylibGum; declarations keep compiling; the user never names the obsolete type, so the modern path is warning-free. Do not propose "completing" this by retyping Default to Gum.GumService or removing the shims — that would break back-compat and is not planned (stable for the foreseeable future). The fact that Default's declared type is an obsolete shim is not a problem and must not be raised as a follow-up.

Not the CLI. Gum.Cli / Gum.ProjectServices are separate tools for headless project validation and codegen.

Lifecycle

GumService.Default.Initialize(game)   // one-time setup
  ↓ per frame:
GumService.Default.Update(gameTime)
GumService.Default.Draw()
  ↓ on teardown (optional):
GumService.Default.Uninitialize()

Initialize throws if called twice without an intervening Uninitialize.

Only the gumProjectFile overload loads a project. Initialize(game, gumProjectFile) loads the .gumx and runs the project-load path — which applies project-level settings (standard-element defaults, localization, and the project's TextureFilterRenderer.TextureFilter, issue #3199). The Initialize(game, DefaultVisualsVersion) / parameterless overloads are code-only and never touch that path. So when manually verifying anything that depends on a loaded project, you must pass the .gumx path or the behavior under test never runs. The cheapest from-file smoke test is Initialize(game, "GumProject/GumProject.gumx") plus a SpriteRuntime (SourceFileName set, scaled up) added to Root.

Singleton Pattern

Default is lazily initialized via ??=. Uninitialize() sets _default = null, so after teardown GumService.Default creates a fresh instance — any stored reference to the old instance is now orphaned.

Uninitialize — Non-Obvious Details

Uninitialize() resets a large amount of shared static state across multiple singletons. Key things it does that are surprising:

  • Nulls GraphicalUiElement.SetPropertyOnRenderable, AddRenderableToManagers, etc. — delegates wired by FormsUtilities.InitializeDefaults
  • Calls ElementSaveExtensions.ClearRegistrations() — clears RegisterGueInstantiation / RegisterDefaultInstantiationType callbacks
  • Calls LoaderManager.Self.DisposeAndClear() — disposes GPU content and empties the cache
  • Nulls and removes FrameworkElement.PopupRoot and FrameworkElement.ModalRoot from managers
  • Resets FileManager.RelativeDirectory to "Content/" (only meaningful if a project was loaded)
  • Calls _systemManagers.Renderer.Uninitialize() (XNALIKE only)
  • Sets _default = null — next access to Default creates a new GumService

FormsUtilities.Uninitialize() is internal; tests access it via InternalsVisibleTo.

Roots

Property Purpose
Root Main scene container; sized to canvas on each Update
PopupRoot Overlaid above Root; for non-modal popups
ModalRoot Topmost layer; blocks input to everything below

PopupRoot and ModalRoot are FrameworkElement statics, not instance fields — they are shared across all GumService instances.

Key Files

File Purpose
MonoGameGum/GumService.cs Main class (namespace Gum)
MonoGameGum/GumServiceCompat.cs [Obsolete] subclass shims for MonoGameGum.GumService / RaylibGum.GumService; also holds the AddChild codegen crutch and ToGraphicalUiElement forwarder
MonoGameGum/Forms/FormsUtilities.cs Input/cursor/gamepad setup; Uninitialize() lives here
GumRuntime/ElementSaveExtensions.GumRuntime.cs ClearRegistrations() called during Uninitialize
RenderingLibrary/Content/LoaderManager.cs DisposeAndClear() called during Uninitialize
Tests/MonoGameGum.Tests.V2/GumServiceUninitializeTests.cs Tests for GPU-accessible Uninitialize behavior
Tests/Gum.ProjectServices.Tests/UninitializeTests.cs Tests for non-GPU Uninitialize behavior

Testing Split

Uninitialize tests are split across two projects because FormsUtilities, LoaderManager, and ElementSaveExtensions don't all require a GPU:

  • Gum.ProjectServices.TestsLoaderManager, ElementSaveExtensions, ObjectFinder (no GPU needed)
  • MonoGameGum.Tests.V2FormsUtilities, root containers, FrameworkElement statics (require test setup with a mock SystemManagers)

Hot Reload

GumService.EnableHotReload(absoluteGumxSourcePath) wires up a GumHotReloadManager that watches the source project directory and rebuilds Root.Children when .gumx/.gusx/.gucx/.gutx/.fnt files change. GumService.Update ticks it each frame; Uninitialize stops and nulls it. For details on the reload pipeline, debounce, font cache eviction, and gotchas, load the gum-runtime-hot-reload skill. Public docs: docs/code/hot-reload.md.

Install via CLI
npx skills add https://github.com/vchelaru/Gum --skill gum-service
Repository Details
star Stars 547
call_split Forks 77
navigation Branch main
article Path SKILL.md
More from Creator