02 TextMode – Getting Started

8 min read

Get a character grid on screen and print to it, so you can see TextMode working in your own project before you commit to building anything on it.

By the end of this page you’ll have a character grid rendering in your scene and your own text printed onto it. It takes about five minutes, and you won’t need to author a font, a material, or a configuration asset to get there: TextMode falls back to sensible defaults for all three. The TextMode Wizard can build the scene setup for you, or you can add each piece by hand.

Installation

Import the package the usual way:

  1. Open Window > Package Manager, choose Add package from tarball, and pick the Scylla TextMode .tgz. If you bought through the Asset Store, import it from My Assets instead.
  2. TextMode depends on Scylla Core, so import that first if it isn’t already in the project.
  3. Import the demos if you want them. The roguelike, terminal and effects demo scenes are the fastest way to see what the module does, and the roguelike in particular is a complete game rather than a feature showcase.
  4. If you want the CRT on a whole camera picture in URP or HDRP, import the matching package from the Extras folder inside the TextMode package: double-click Scylla TextMode for URP or Scylla TextMode for HDRP in the Project window, or choose Assets > Import Package > Custom Package… and select it. Each one has a Demos package beside it, which you import afterwards if you want the demo. Import only the one for your project’s render pipeline.

TextMode needs TextMeshPro, which ships with Unity. You don’t need to configure it; the module loads a default monospace SDF font asset on its own if you don’t assign one.

The TextMode Wizard

The quickest way to a working setup is the TextMode Wizard, at Tools > Scylla > TextMode > TextMode Wizard…. It asks a handful of questions and then builds the whole setup in the open scene: the bootstrap and the module if they are missing, a configuration with the project’s color theme, a camera, the display itself, and optionally a terminal and a CRT.

The first page is an introduction. After that, each page covers one part of the setup and explains what its options mean, so you can work through it without knowing the module yet:

  • Setup Type offers a typical setup to start from. Each one fills in the remaining pages with sensible values, and every page has a Reset to Defaults button that returns to them.
  • Display decides whether the grid draws on the screen, through a canvas, or as a surface in the scene. It also sets the grid size: either as many cells as fit the area, or a fixed number of columns and rows.
  • Text & Input sets the font, the font size and spacing, the cell border and the cursor. It also sets up text selection and copying.
  • Colors & Theme chooses the color theme and where the display takes its colors from.
  • Terminal turns the display into a terminal with a scrolling log and a command line, or a full-screen terminal for a program that draws its own screen. This page is only shown for a display on the screen.
  • CRT Shader shows the display, or the whole camera picture, through a simulated CRT monitor, starting from one of the presets.
  • Review & Create lists everything the wizard is about to create. Click Create TextMode Setup to build it.

These are the typical setups the wizard offers:

SetupWhat it creates
Grid-based GameA fixed 80 by 25 grid on the screen that game code writes cells into, in the Classic theme, through the CGA Monitor CRT.
Text AdventureA screen-filling log with a command line the player types into, in the Amber Phosphor theme, through the Clean Readable CRT.
In-World MonitorA fixed 80 by 25 grid placed in the scene as the screen of an in-game computer, in the Green Phosphor theme, through the Green Terminal CRT.
Terminal / ShellA shell-style terminal with a scrolling log and a command line, in the Amber Phosphor theme, through the Standard Terminal CRT.
CustomA plain grid on the screen with default settings, ready to be set up page by page.

Everything the wizard adds to the scene is one Undo step, so a single Undo removes it again. The assets it creates stay in the project: the configuration and, for a camera CRT, a Volume profile. Running the wizard again reuses the TextMode configuration the module already has, or the one it created last time, instead of adding another copy.

Setup and Configuration

To set TextMode up by hand instead, add the pieces one at a time. TextMode is a module, so it lives under the framework bootstrap.

  1. If the scene has no bootstrap yet, add one with Tools > Scylla > Create > Scylla Core.
  2. Add the module with Tools > Scylla > Create > Scylla TextMode. It’s created as a child of the bootstrap, which is where the module system expects to find it. Only one is allowed per scene; the menu item tells you if there’s already one there.
  3. Add a view. This is the component that actually renders, and there are two of them depending on where you want the grid:
    • UITextModeView goes on a GameObject under a Canvas. It’s a Canvas graphic, so it respects masks, RectMask2D clipping and CanvasGroup alpha. Use this for overlays, menus, and anything screen-space.
    • TextModeView goes on a plain GameObject in world space. Use this for a monitor on a wall, a terminal the player walks up to, or anything the camera can move around.

That’s the whole setup. The view sizes its own grid from the font size and the space it’s given, so you’ll see a grid the moment you press play.

A ScyllaTextModeConfiguration asset is optional. Without one the module builds a default configuration at runtime, which is fine while you’re finding your feet. When you do want to tune the grid, the SDF rendering, the terminal or the effects, create the asset and assign it on the module; see Configuration for what each setting does and how the JSON config file mirror lets you retune a shipped build.

Usage

You draw by writing cells into the view’s grid. The friendliest way in is TextModeConsole, which wraps the grid with the operations a text display actually needs.

using Scylla.TextMode;
using UnityEngine;

public class ShipConsole : MonoBehaviour
{
    [SerializeField] private UITextModeView _view;

    private TextModeConsole _console;

    private void Start()
    {
        /* The console is a thin writer over the view's grid. It needs the glyph cache too, so it
           can stamp the right atlas coordinates into each cell as it writes. */
        _console = new TextModeConsole(_view.Grid, _view.GlyphCache);

        DrawStatusScreen();
    }

    private void DrawStatusScreen()
    {
        /* Clear to the view's default colors before drawing a fresh screen. */
        _console.Clear();

        /* A framed panel. Five box styles ship: Single, Double, Rounded, Heavy and ASCII. */
        _console.DrawBox(0, 0, _view.Columns, _view.Rows, BoxStyle.Double,
            ANSIColor.BrightCyan, ANSIColor.Black);

        /* Centered on its row, so the title stays put when the grid resizes. */
        _console.PrintAligned(2, "LIFE SUPPORT", TextAlignment.Center,
            ANSIColor.BrightWhite, ANSIColor.Black, CellAttributes.Bold);

        /* Ordinary printing takes a position, a color pair, and optional attributes. */
        _console.Print(4, 5, "OXYGEN    NOMINAL", ANSIColor.Green, ANSIColor.Black);
        _console.Print(4, 6, "COOLANT   NOMINAL", ANSIColor.Green, ANSIColor.Black);

        /* Blink is a cell attribute the shader animates, so a warning costs no per-frame work. */
        _console.Print(4, 7, "HULL      BREACH", ANSIColor.BrightRed, ANSIColor.Black,
            BackgroundBlendMode.Set, CellAttributes.Bold | CellAttributes.Blink);
    }
}

Assign your view to the _view field, press play, and the panel is on screen.

A few things worth knowing early:

  • Coordinates are cell coordinates, column then row, with the origin at the top left. The console takes (x, y); the grid itself takes (row, column), which is worth remembering the first time you reach past the console.
  • Writes are cheap. Changing a cell marks its row dirty, and the view uploads only the dirty range in LateUpdate. You don’t need to batch your drawing or avoid redrawing every frame.
  • Colors come from anywhere. ANSIColor gives you the standard sixteen by name, ANSIColor.FromIndex reaches the 256-color palette, and ANSIColor.FromRGB takes any truecolor value. Anything that produces a Color32 works. See Colors and Attributes.

Once the grid is drawing, the rest of the module is opt-in. For a terminal the player types into, reach for Terminal Frontend. To animate the screen, Text Effects. To let the player restyle it, Color Themes.

Troubleshooting