Surfaces and consoles overview
Everything you see in a SadConsole game draws through a surface. A surface is a 2D grid of cells, where each cell holds a glyph, a foreground color, and a background color. Surfaces are the foundation of every visual object in SadConsole, from simple text displays to full windowed UIs.
Choosing the right type
Section titled “Choosing the right type”Pick the type that matches what you need:
| Type | Use it when you want to… |
|---|---|
ScreenObject | Organize children without rendering any cells. |
ScreenSurface | Display glyphs, draw shapes, or show static content. |
Console | Accept keyboard input or use a cursor for text printing. |
ControlsConsole | Host UI controls like buttons, text boxes, and checkboxes. |
Window | Show a bordered, titled, draggable panel or dialog. |
AnimatedScreenObject | Play a frame-by-frame cell animation. |
LayeredScreenSurface | Stack multiple independent cell layers on one surface. |
Object hierarchy
Section titled “Object hierarchy”SadConsole organizes its display objects in a clear hierarchy. Each type builds on the one before it, adding more capability:
ScreenObject ├─ AnimatedScreenObject └─ ScreenSurface ├─ LayeredScreenSurface └─ Console ├─ ControlsConsole └─ WindowScreenObject: the base of every SadConsole object. Provides positioning, parent/child relationships, components, and input processing. It doesn’t render any cells on its own.ScreenSurface: adds a cell surface, a font, and a renderer. This is the most common type you’ll use when you just want to display something on screen.Console: extendsScreenSurfacewith a cursor for text input and keyboard handling.ControlsConsole: extendsConsolewith a built-in control host for UI controls like buttons, checkboxes, and lists.Window: extendsConsolewith a title bar, border, dragging support, and modal display. Also includes a built-in control host.AnimatedScreenObject: extendsScreenObjectdirectly and implementsIScreenSurface. Holds a list of cell surface frames and plays them back over time.LayeredScreenSurface: extendsScreenSurfacewith aLayeredSurfacecomponent, allowing multiple independent cell layers to be stacked and rendered together.
Cells and CellSurface
Section titled “Cells and CellSurface”At the lowest level, a surface is an array of ColoredGlyph objects managed by an ICellSurface. Each cell stores three pieces of information:
- Foreground color: the color of the glyph character.
- Background color: the color behind the glyph.
- Glyph index: the index into the font texture that determines which character or tile to display.
The CellSurface class implements ICellSurface and provides the actual cell array. You can set individual cells, print text, draw shapes, and apply effects through the surface.
// Access individual cells on a surfacescreenSurface.Surface[5, 3].Glyph = (int)'A';screenSurface.Surface[5, 3].GlyphCharacter = 'A';screenSurface.Surface[5, 3].Foreground = Color.Yellow;screenSurface.Surface[5, 3].Background = Color.DarkBlue;Parent-child relationships
Section titled “Parent-child relationships”All screen objects support a parent-child hierarchy through the Children collection. Child objects render relative to their parent’s position and inherit visibility and update behavior.
ScreenSurface parent = new(80, 25);ScreenSurface child = new(20, 10);child.Position = new Point(5, 5);
parent.Children.Add(child);
GameHost.Instance.Screen = parent;Any ScreenObject-based type can serve as a child of another. This lets you compose complex layouts by nesting surfaces, consoles, and windows together.
ScreenObject
Section titled “ScreenObject”ScreenObject is the base class for everything in SadConsole. It doesn’t draw any cells—it exists purely to provide the shared infrastructure all other types depend on:
- Position: tracks where the object sits on screen, both relative to its parent and absolute in screen space.
- Children: a collection of child
IScreenObjectinstances that render and update along with their parent. - Components: a list of
IComponentobjects that extend behavior without subclassing. - Input: routes keyboard and mouse events to the object and its components.
- Visibility and focus: controls whether the object renders and whether it receives keyboard input.
Use ScreenObject directly when you need an invisible container to group and position other objects without rendering anything itself.
ScreenObject container = new();container.Position = new Point(10, 5);
ScreenSurface panel = new(20, 10);container.Children.Add(panel);
GameHost.Instance.Screen = container;ScreenSurface
Section titled “ScreenSurface”The ScreenSurface type is the most commonly used object in SadConsole. It wraps a CellSurface with everything needed to display it on screen: a font, a font size, a renderer, and a position.
Create a ScreenSurface by specifying the width and height in cells:
ScreenSurface surface = new(80, 25);surface.Surface.Print(1, 1, "Hello, SadConsole!");surface.Position = new Point(5, 5);
GameHost.Instance.Screen = surface;View and buffer
Section titled “View and buffer”A ScreenSurface can have a total buffer size larger than the visible area. The view controls which portion of the buffer you see. This is useful for scrolling maps or large text areas:
// Create a surface with a 40x20 visible area, backed by a 200x100 bufferScreenSurface bigSurface = new(40, 20, 200, 100);
// Scroll the viewbigSurface.ViewPosition = new Point(10, 5);Key properties
Section titled “Key properties”| Property | Description |
|---|---|
Surface | The underlying ICellSurface containing all cells. |
Font | The font used to render glyphs. |
FontSize | The pixel size of each cell. |
Tint | A color overlay applied to the entire surface. |
UsePixelPositioning | When true, positions the surface by pixel instead of by cell. |
Console
Section titled “Console”The Console type inherits from ScreenSurface and adds a Cursor component. The cursor lets you print text at a tracked position, handle keyboard input, and create classic terminal-style interactions.
Console console = new(80, 25);console.Cursor.IsVisible = true;console.Cursor.IsEnabled = true;console.Cursor.PrintAppearanceMatchesHost = false;console.Cursor.Print("Type something: ");
GameHost.Instance.Screen = console;Key differences from ScreenSurface:
- Has a
Cursorproperty for text input and printing. - Keyboard input is enabled by default.
- Supports
AutoCursorOnFocusto show or hide the cursor based on focus state.
ControlsConsole
Section titled “ControlsConsole”The ControlsConsole type combines a Console with a ControlHost component. This gives you a surface that can display and manage UI controls like buttons, text boxes, checkboxes, and list boxes.
ControlsConsole controlsConsole = new(60, 20);
Button button = new("Click Me", 12);button.Position = new Point(2, 2);button.Click += (s, e) => controlsConsole.Cursor.Print("Button clicked!");
controlsConsole.Controls.Add(button);
GameHost.Instance.Screen = controlsConsole;The Controls property exposes the ControlHost, where you add, remove, and manage controls. You can also add a ControlHost manually to any ScreenSurface without using ControlsConsole:
ScreenSurface surface = new(60, 20);ControlHost controls = new();surface.SadComponents.Add(controls);
Button button = new("OK", 6);controls.Add(button);For more details about UI controls, see the controls overview.
Window
Section titled “Window”The Window type provides a bordered, titled surface that you can drag, show modally, and dismiss. It inherits from Console and includes its own ControlHost, making it ideal for dialog boxes, settings panels, and popup menus.
Window window = new(40, 15);window.Title = "Settings";window.CanDrag = true;window.CloseOnEscKey = true;window.Center();window.Show(true); // Show as modalWindow features
Section titled “Window features”- Title bar: displays a title string along the top border. Control alignment with the
TitleAlignmentproperty. - Dragging: set
CanDragtotrueto let users move the window with the mouse. - Modal display: call
Show(true)to display the window modally, blocking input to objects behind it. - Close on Escape: set
CloseOnEscKeytotrueso pressing Escape hides the window. - Built-in controls: access the
Controlsproperty to add UI controls directly.
Window dialog = new(30, 10);dialog.Title = "Confirm";dialog.CanDrag = false;
Button yesButton = new("Yes", 6);yesButton.Position = new Point(5, 5);yesButton.Click += (s, e) => { dialog.DialogResult = true; dialog.Hide(); };
Button noButton = new("No", 6);noButton.Position = new Point(15, 5);noButton.Click += (s, e) => { dialog.DialogResult = false; dialog.Hide(); };
dialog.Controls.Add(yesButton);dialog.Controls.Add(noButton);dialog.Center();dialog.Show(true);LayeredScreenSurface
Section titled “LayeredScreenSurface”LayeredScreenSurface extends ScreenSurface and adds a LayeredSurface component. This lets you stack multiple independent cell layers on a single surface—useful for tile maps with separate foreground, background, and decoration layers.
The base surface from ScreenSurface automatically becomes the first layer. Add more layers through the Layers property:
LayeredScreenSurface layered = new(80, 25);
// The base surface is layer 0 automatically// Add a second layerICellSurface layer1 = layered.Layers.Add();layer1.Print(5, 5, "Overlay text");
GameHost.Instance.Screen = layered;Each layer is a full ICellSurface rendered in order, with transparent cells letting layers below show through. Resize operations on LayeredScreenSurface propagate to all layers through the Layers component.
AnimatedScreenObject
Section titled “AnimatedScreenObject”AnimatedScreenObject extends ScreenObject directly and implements IScreenSurface. Instead of a single cell surface, it holds a Frames collection of ICellSurface objects and advances through them automatically based on a configurable AnimationDuration.
Create an animation by adding frames and then calling Start():
AnimatedScreenObject animation = new("walk", 4, 4);
// Add frames and draw content into each oneICellSurface frame1 = animation.CreateFrame();frame1.SetGlyph(1, 1, '@');
ICellSurface frame2 = animation.CreateFrame();frame2.SetGlyph(2, 1, '@');
animation.AnimationDuration = TimeSpan.FromSeconds(0.5);animation.Repeat = true;animation.Start();
GameHost.Instance.Screen = animation;SadConsole also provides a static helper to generate noise-effect animations:
AnimatedScreenObject noise = AnimatedScreenObject.CreateStatic(20, 10, 8, 0.3);GameHost.Instance.Screen = noise;Key properties and methods:
Frames: The list ofICellSurfaceobjects that make up the animation.AnimationDuration: The total time to play through all frames once.Repeat: Whentrue, the animation loops.Start()/Stop()/Restart(): Control playback.CurrentFrameIndex: The index of the frame currently displayed.