Default Theme Icons

Forma embeds the same default icon manifest in its MonoGame and FNA packages. Applications do not need MGCB, XNB files, an SVG parser, or copied content assets. The PNG atlases remain the native-free default and fallback. A matching explicit SVG backend companion also packages the authoritative SVG sources for exact-scale runtime rendering. assets/theme-icons/imports.json owns the current icon inventory; this guide intentionally does not duplicate its count.

Set UIContext.ThemeIconRenderingPolicy to BitmapAtlas, RuntimeSvg, or Auto. Runtime SVG keeps the selected PNG atlas available as a per-icon fallback, so a missing backend or unsupported source never removes the current default icon. ThemeIconDiagnostics reports the selected density, runtime SVG icon count, PNG fallback count, missing lookups, atlas memory, and cache generation. See runtime-svg.md for backend setup and security limits.

Renderer Selection

The build spike compared Svg.Skia with SVG.NET. Svg.Skia was selected because it uses the same cross-platform Skia raster path on macOS, Linux, and Windows, exposes explicit sRGB premultiplied RGBA output, and does not rely on System.Drawing.Common. SVG.NET's normal bitmap path uses System.Drawing, which is supported only on Windows in current .NET and therefore cannot provide the same clean-checkout command on all CI operating systems. Svg.Skia 5.2.0 and SkiaSharp 4.148.0 are pinned in central build properties; CI regenerates and byte-compares output on every supported host.

Ownership and Density

UIContext lazily decodes the embedded PNG atlas on its render thread after receiving a valid graphics device. Contexts sharing one device reuse a weak-keyed device cache; the last context disposes the textures. A disposed atlas is recreated on the next draw. ThemeIcon values are non-owning atlas views and must not dispose application or cache textures.

The 1x atlas is selected below a display scale of 1.5; the 2x atlas is selected at 1.5 and above. Scales below 1x use the 1x atlas, and scales above 2x use the 2x atlas. Logical icon dimensions do not change with density. Linear clamping and two logical pixels of transparent atlas padding avoid neighbor bleed at fractional scales.

The current canonical payload is approximately 40 KB of PNG data. Decoded texture memory is about 274 KB for 1x and 1.05 MB for 2x. Atlases are loaded on demand, so a context normally retains only the densities it has displayed.

Rollout Budgets

The current peer packages are 328 KB each. Icon rollout budgets are: no more than 128 KB of compressed icon/manifest payload, no more than 350 KB per core peer package, no more than 1.1 MB for the active 2x texture, and no more than 1.4 MB if both densities have been visited on one device. The canonical values are 274,432 decoded bytes at 1x and 1,097,728 bytes at 2x.

All default icons for one density occupy one atlas page. A control sequence using only default icons therefore introduces at most one default-icon texture per density, without per-icon texture switches. The lifecycle test requires cache generation to remain unchanged across repeated warm Ensure calls, proving warm frames perform no image decode, texture creation, or atlas allocation. Cold load is bounded by one embedded PNG decode and one upload for each density first displayed.

Customization

Theme icons are type-scoped and inherited in the same derived-to-base order as style boxes:

var customTheme = new Theme { Parent = context.Theme };
customTheme.SetIcon("arrow", customArrow, nameof(OptionButton));
option.ThemeOverride = customTheme;

RemoveIcon reveals inherited/default values. SuppressIcon intentionally hides an inherited icon. Per-control AddThemeIconOverride, RemoveThemeIconOverride, and SuppressThemeIcon provide the same behavior locally. Existing Texture2D properties on buttons, menu items, tabs, tree cells, graph ports, and gutters remain application-owned content icons and take precedence where present.

Regeneration

make icons-verify regenerates the canonical 1x/2x PNG atlases and JSON metadata and fails on byte drift. make icons updates canonical outputs from the already imported SVG inputs. A reviewed source update requires a Godot checkout at the revision recorded in assets/theme-icons/imports.json:

make icons-import GODOT_ROOT=../godot
make icons
make icons-verify

The pipeline rejects duplicate names or sources, editor-only paths, missing mappings, unclassified licenses, zero-sized SVGs, source hash drift, and incomplete density output.

Intentional Exclusions

Only runtime icons mapped to behavior Forma currently exposes are imported. Dialog/window close icons, ColorPicker pipette/shape/overbright icons, tab drop marks, and CodeEdit completion-color backgrounds remain excluded until corresponding interactive behavior exists. Godot's editor icon collection is excluded entirely.

Catalog Stories

The exact theme-icon story names are Complete icon inventory, Runtime SVG, Override and suppression, and Atlas diagnostics. Their stable identifiers are the kebab-case names prefixed with catalog-, such as catalog-runtime-svg.