Debug Overlay
DebugOverlay is one block of on-screen text, assembled from sections contributed by whatever has
something to say - the camera controller's key help, your own instructions, a live counter - with one
position and one hide key for the lot. It is a game system, so it survives scene swaps and draws
itself every frame; nothing calls it.
Use it instead of game.DebugTextSystem.Print(...) from several scripts, whose hand-placed lines
overlap and are unreadable on a high-DPI display.
DebugOverlay, DebugOverlaySection and TextElement live in the
Stride.CommunityToolkit.Rendering.Text namespace; ScreenAnchor in Stride.CommunityToolkit.Rendering.
Adding text
Get the shared instance and add a section. The callback runs every frame the overlay is drawn, so
values that change need no pushing - this is E02_3D_Primitives:
var overlay = DebugOverlay.GetOrCreate(game);
overlay.AddSection("Game", static () =>
[
new("P", "Show or hide the collidable gizmos", Color.Gold),
new("F11", "Show or hide the debug meshes", Color.Gold),
new("R", "Reset the scene", Color.Gold),
]);
Each TextElement is a line, an optional key and an optional colour; a line without a colour uses
DefaultTextColor. Sections are sorted by order and separated by SectionGap blank lines (default
1; 0 runs them together). The camera controllers register their help at order -100, so anything
added without an order lands below it.
A section can collapse to a single title line and expand again on a key:
overlay.AddCollapsibleSection("Physics", "Physics", Keys.F5, () => [ ... ], collapsed: true);
That is how [+] [F2] Camera controls is drawn: the marker, then the key, then the title, with the body indented one marker. AddSection and AddCollapsibleSection return the DebugOverlaySection, so a section can be disabled, collapsed or removed later.
Keys are data, not text. A help line names them - new("H", "Reset camera", Color.Gold), or
new(["Q", "E"], "Ascend / descend") for keys that do the same thing, or new("Arrow keys", "Move") -
and the overlay decorates them when it draws: each key through KeyFormat (default [{0}]), joined by
KeySeparator, in KeyColor, which defaults to the line's colour blended halfway to white.
overlay.KeyFormat = "{0}:" restyles every help line from [F2] to F2:. A line with no keys is
drawn as given.
BlockBounds is the rectangle the block was last drawn in, in screen pixels; E02_2D_Easing reads it to place its panel under the block each frame.
Tip
Something that already knows how to describe itself as lines - DebugTextDropdown.GetLines(), for
example - plugs straight in: overlay.AddSection("Spawn", () => spawnMenu.GetLines()), as
E04_2D_SpawnMenu does.
Keys and position
| Key or property | Default | Does |
|---|---|---|
ToggleKey |
F4 | Hides and shows the whole overlay. |
RepositionKey |
F3 | Cycles the corners: top-left, top-right, bottom-right, bottom-left. |
Position |
TopRight |
The ScreenAnchor: a corner, the middle of an edge or the centre. null uses CustomPosition instead; Visible = false draws nothing. |
Margin |
5, 10 |
Distance from the edges, in unscaled pixels. |
Section keys are read even while the overlay is hidden, so a collapse toggle pressed with everything off still takes effect.
Note
The camera controllers claim W A S D, Q E, the arrow keys, the numeric keypad, H and F2; the overlay itself claims F3 and F4. Bind section toggles and example keys elsewhere; G is the reference grid's and T the grabbers'. Safe single letters include J K L M N P R Z.
Size, and high-DPI displays
The overlay draws with a font rasterised at the size asked for, so it is sharp at any size. It
follows the display by default: on a laptop at 150% it draws one and
a half times larger than on a monitor at 100%, so it reads the same size to the eye on both. The
factor comes from DisplayScale, which is shared with everything else that draws in pixels and is
re-read when the window moves to a differently scaled monitor. Three properties control the rest:
AutoScaleis that behaviour, on by default. Turn it off to draw at exactlyScale, for a screenshot at a known size or when the game applies its own UI-scale setting.Scalemultiplies everything - text, line spacing, margins, padding - on top of the display's factor, so the block keeps its layout. It is a preference, "a bit bigger", not a DPI figure:1.25on a 150% display draws at 1.875.FontSizeis the text height at scale 1 on a 100% display, in pixels. Defaults to 14.
The display factor is only right if the process is DPI aware - otherwise Windows is already
stretching the whole window and the factor correctly reads 1. Declare awareness in an
app.manifest, as the Stride templates do, or call WindowsDpiManager.EnablePerMonitorV2() (in the core
package, namespace Stride.CommunityToolkit.Engine) before the game is created; see the
DPI-aware example.
Fonts
Stride's default font asset is bold. The overlay looks for an installed system font instead,
picked by FontFamily:
FontFamily |
Windows | macOS | Linux |
|---|---|---|---|
Monospace (default) |
Consolas, Cascadia Mono, Courier New, DejaVu Sans Mono | Menlo, Courier New, DejaVu Sans Mono | DejaVu Sans Mono, Liberation Mono, Courier New |
SansSerif |
Segoe UI, Arial, DejaVu Sans | Helvetica, Arial, DejaVu Sans | Liberation Sans, DejaVu Sans, Arial |
The first family found in the system font folders wins. Monospace is the default so that columns line up and a number does not shift its neighbours as its digits change.
To be specific rather than pick a family:
FontName = "Cascadia Mono"names an installed family;FontStylechoosesRegular,Bold,ItalicorBoldItalic.FontFile = "/path/to/font.ttf"points at a file that is not in the system font folders.Font = someSpriteFontsupplies a font asset of your own and overrides all of the above.- When none of the candidates is installed, or the named font fails to load, the overlay falls back to Stride's default font and logs one warning naming the fonts tried.
The lookup finds files by the common naming conventions (consola.ttf, LiberationMono-Regular.ttf,
DejaVuSansMono.ttf); it does not consult fontconfig, so an unusually named file needs FontFile.
Background
Each line gets a strip behind it, exactly as wide as its text:
| Property | Default | Notes |
|---|---|---|
BackgroundColor |
black at 49% alpha | The look of Stride's debug text. Color.Transparent draws no strip. |
BackgroundPadding |
3, 1 |
How far the strip extends beyond the text, in unscaled pixels. |
DefaultTextColor |
LightGreen |
For lines that give no colour. |
TitleColor |
null |
Section titles; null means DefaultTextColor. |
On a light scene the default strip is too faint to carry light-coloured text. Darken it, or invert the scheme:
// E11_2D_Charts, a white 2D scene
overlay.BackgroundColor = new Color(0, 0, 0, 200);
// Or a light strip with dark text
overlay.BackgroundColor = new Color(255, 255, 255, 230);
overlay.DefaultTextColor = Color.Black;
Line spacing
LineHeight is null by default, which means the distance between lines is worked out from the
font: text height, plus the padding above and below, plus LineSpacing (default 2 pixels). Change
FontSize and the lines follow. LineSpacing = 0 makes the strips touch; a fixed LineHeight in
unscaled pixels overrides the calculation entirely.
What it is not
- Not part of the graphics compositor. It draws straight to the back buffer after everything else, so it is always on top and unaffected by post effects, and it needs nothing registered in the compositor.
- Not a UI toolkit. One block of lines in a corner. Anything laid out in the scene wants entity text or world text; anything interactive wants Stride UI or the ImGui package.
Where it is used in the toolkit
| Piece | In E11_2D_Charts |
Concept |
|---|---|---|
DebugOverlay.GetOrCreate(game) |
Program.cs, Start |
one shared instance, registered as a service |
WindowsDpiManager.EnablePerMonitorV2() |
Program.cs, before new Game() |
a sharp window; the overlay's size then follows DisplayScale on its own |
overlay.BackgroundColor = new Color(0, 0, 0, 200) |
Program.cs, Start |
readable on a white scene |
overlay.AddSection("Chart", () => [...]) |
Program.cs, Start |
a live key line: [G] Grid on |
SceneSetup2D |
Program.cs, game.Run(...) |
adds the 2D camera controller, whose collapsible [+] [F2] Camera controls section is at order -100 |