The settings asset behind every TextMode view, and the JSON config file that lets you retune a shipped build without recompiling it.
Summary
ScyllaTextModeConfiguration is the ScriptableObject that holds the module’s defaults: how big a view starts, how sharp the text is, how the terminal behaves, what the effects do, and which color theme comes up. Assign one on the TextMode module and every view in the scene starts from it.
You do not need one to get going. When the module initializes and finds no asset assigned, it looks for one in Resources under the framework’s config folder, and failing that it builds a default configuration in memory. That is why a freshly added TextMode module renders without any setup at all, and why the log line about initializing from defaults is informational rather than a warning.
The reason to create the asset is the second half of the story. Like every Scylla configuration, this one mirrors to a JSON config file with the framework’s four-tier fallback, so a value can be overridden from the user’s Documents folder, from alongside the application, from an asset in the project, or left at its compiled-in default. That is what lets a player, a QA tester, or you on a support call change the scrollback depth or turn off motion in a shipped build without a new binary. See Configuration in Core for how the tiers resolve.
Settings are grouped by what they touch: Grid, SDF, Terminal, Effects, Theme and Debug. Views read the ones that affect them when they initialize, and a handful of static resolvers let runtime code ask the active configuration a question without holding a reference to the module.
Use the configuration for:
- Setting the default size and sharpness every view starts from.
- Tuning terminal behavior: scrollback depth, tab stops, wrapping, blink rates.
- Turning effects off wholesale, or capping how many run at once.
- Choosing the color theme the game comes up in.
- Shipping a build whose text behavior can be retuned from a config file.
Features
- One asset, six groups. Grid, SDF, Terminal, Effects, Theme and Debug, each a serialized class with its own Inspector section.
- Optional. No asset means a runtime default, so nothing breaks before you have made one.
- JSON config file mirror. Every group exports to and imports from a config file, so a shipped build can be retuned in the field.
- Four-tier fallback. User Documents, then application folder, then a project asset, then the compiled defaults. The first tier that supplies a key wins.
- Validation with severity. Values are checked when the configuration is applied, and anything at error severity aborts startup rather than producing a display that silently misbehaves.
- Static resolvers.
TryResolveActiveSDF,TryResolveBlinkRates,TryResolveDefaultLineHeight,TryResolveEffectSettingsandTryResolveThemeSettingslet a component read the active settings without a reference to the module, and fall back cleanly when no module is present. - Accessibility switch. A reduced-motion flag the effects system honors, so a player who needs less movement gets it everywhere at once, rather than effect by effect.
Settings
Grid
These are the defaults a new view starts from. A view can override any of them in its own Inspector, so this group only decides what a freshly added one looks like.
| Setting | Default | Effect |
|---|---|---|
| Default Font Size | 16 | Starting font size for a new view, in points. Drives cell size and therefore the computed column and row counts. |
| Default Pixels Per Unit | 80 | World-space scaling for TextModeView. How many pixels of font map to one Unity world unit, so a larger value gives a physically smaller display. Ignored by the Canvas view, which works in canvas units. |
| Default View Width | 8.0 | Starting width in world units for a world-space view. |
| Default View Height | 5.0 | Starting height in world units for a world-space view. |
SDF
These are the dials that decide how the distance-field renderer draws glyphs, and whether the text ends up crisp, soft, or over-sharpened.
| Setting | Default | Effect |
|---|---|---|
| Threshold | 0.5 | The distance-field value treated as the glyph edge. Lowering it thickens every glyph, raising it thins them. Leave it at the midpoint unless you are compensating for an unusual font atlas. |
| Smoothing | 1.0 | Edge sharpness. One puts the anti-aliasing ramp exactly one screen pixel wide, which is as crisp as an edge gets without aliasing. Lower values soften it; higher values harden it toward aliasing. Independent of the font’s atlas padding, so the same value looks the same on every font. |
| Bold Weight | 1.5 | How far the faux-bold pass dilates a glyph, in atlas texels. Working in texels keeps bold consistent across fonts built with different padding. Too large rounds corners and softens edges. |
| Italic Shear | 0.2 | Horizontal shear for the faux-italic pass, as a fraction of cell height. |
| Default Line Height | 1.0 | Starting line-height multiplier for a new view. A starting value rather than an override, so a terminal driving its own line spacing keeps it. Below about 0.82 the cell becomes shorter than the glyphs are tall and neighboring rows draw the overhang. |
Terminal
These settings control the behavior of the emulator and the frontend. See Terminal and Terminal Frontend.
| Setting | Default | Effect |
|---|---|---|
| Scrollback Lines | 1000 | How many scrolled-off lines the terminal keeps. Backed by a ring buffer, so the cost is bounded and paid up front rather than growing during a session. |
| Tab Stop Interval | 8 | Columns between default tab stops, matching terminal convention. Programs can set their own stops at runtime; this is the grid they start from. |
| Default Auto Wrap | On | Whether a character written past the right edge wraps to the next row. Off, text is clipped at the margin. This is the DECAWM mode a program can also toggle with an escape sequence. |
| Wrap Mode | Word | How PrintWrapped breaks lines: Word on spaces, Character anywhere, None clips. Read live by the console unless a caller sets it explicitly. |
| Cursor Blink Rate | 1.0 | Cursor blinks per second. Animated in the shader, so it costs nothing per frame. |
| Text Blink Rate | 1.0 | Blinks per second for cells carrying the blink attribute. Separate from the cursor so the two do not have to agree. |
Effects
These settings give global control over the text effects system. See Text Effects.
| Setting | Default | Effect |
|---|---|---|
| Effects Enabled | On | The kill switch. Off, effects do not run at all, which is the quickest way to isolate whether an effect is behind a visual problem. |
| Global Speed Multiplier | 1.0 | Scales every effect’s rate. Useful for slowing everything down while you tune a sequence, or speeding a demo up. |
| Default Duration | 0.5 | Duration in seconds an effect takes when its own is not set. |
| Typewriter Characters Per Second | 30 | Default typing speed. Because the typewriter derives its duration from the text length, this is what makes a long paragraph take proportionally longer than a short one. |
| Max Concurrent Effects | 16 | How many effects a player can run at once. Reached, further plays are refused rather than queued, which keeps a runaway caller from starving the frame. |
| Publish Character Events | Off | Whether the typewriter raises an event per revealed character. Off by default because it costs one event dispatch per character; turn it on when you want to drive a keystroke sound. |
| Reduce Motion | Off | Accessibility switch the effects honor. Turn it on to spare players who need less movement, rather than removing effects from your code. |
Theme
This group controls which color theme the module comes up in, and what a theme change touches. See Color Themes.
| Setting | Default | Effect |
|---|---|---|
| Theme Name | Scylla TextMode Classic | The palette applied at startup, resolved by name through the Core color asset registry. A name that cannot be resolved falls back to Classic and logs a warning, so a typo degrades rather than breaking. |
| Apply Theme To Views | On | Whether the module pushes the configured theme when it starts. Off, no theme is applied at startup and views keep their own Inspector colors. |
| Remap On Theme Change | On | Whether switching theme recolors content already on the grid, in addition to changing what is drawn next. Off, a theme change affects only new drawing, useful if you are about to redraw the screen anyway. |
Debug
| Setting | Default | Effect |
|---|---|---|
| Log Render Stats | Off | Logs per-frame render statistics. Useful when investigating upload cost, noisy otherwise. |
| Show Grid Outline | Off | Draws a visible outline around the grid, which is the fastest way to see where a view actually is when it renders nothing. |
Recipes
Ship a build a player can retune
Problem. Your game has an in-game terminal and a player on a small screen wants more scrollback than you shipped with, or a player sensitive to motion wants the effects calmed down. You do not want to cut a new build for either.
Solution. Export a config file from the asset, ship it beside the application, and the four-tier fallback does the rest.
/* The Inspector's Export Config File button writes the same thing this does: a JSON file with
every group and key at their current values. Ship it next to the executable and a player
can edit it, or drop one in their Documents folder to override without touching yours. */
var configFile = configuration.ExportToConfigFile();
The file name is fixed, so the loader knows what to look for. Any key present in a higher tier wins; anything absent falls through to the next. That means a player’s file only needs the handful of keys they want to change, not a full copy.
Honor a reduced-motion preference
Problem. A player has motion sensitivity and your title screen has a digital-rain transition, a glitch ambient, and a typewriter reveal. You want one switch that calms all of it rather than auditing every effect call.
Solution. Turn on Reduce Motion in the Effects group, or set it from your own accessibility menu and apply the configuration.
/* One flag the effects system reads, rather than a conditional at every call site. */
configuration.Effects.ReduceMotion = accessibilitySettings.PrefersReducedMotion;
/* Apply pushes the configuration to the systems that read it. */
configuration.Apply();
Read a setting without holding the module
Problem. A component deep in your UI needs to know the configured blink rate, and threading a reference to the TextMode module through to it would mean touching every class in between.
Solution. Use a static resolver. They read the active module’s configuration when there is one, and fall back to sensible values when there is not, so the component also works in a test scene with no bootstrap.
/* Returns false when there is no module or no configuration, and still writes usable values,
so a component in a bare scene behaves rather than throwing. */
if (ScyllaTextModeConfiguration.TryResolveBlinkRates(out var cursorRate, out var textRate))
{
/* Values came from the live configuration. */
}
/* Same shape for the theme settings, the effect settings, the SDF values and the line height. */
ScyllaTextModeConfiguration.TryResolveThemeSettings(out var themeName, out var applyToViews, out var remapOnChange);
Reset an asset you have tuned into a corner
Problem. You have been experimenting with SDF values and the text now looks worse than it did out of the box, and you cannot remember what you changed.
Solution. ResetToDefaults puts every group back to the compiled-in values.
/* The Inspector's Reset to Defaults button calls this. Every group, not just the one you were
editing, so it is a clean slate rather than a partial revert. */
configuration.ResetToDefaults();
API Sketch
class ScyllaTextModeConfiguration : ScyllaConfiguration {
GridSettings Grid;
SDFSettings SDF;
TerminalSettings Terminal;
EffectsSettings Effects;
ThemeSettings Theme;
override void ResetToDefaults();
override void Apply();
override ConfigFile ExportToConfigFile();
override int ApplyConfigFileOverrides(ConfigFile file); /* returns keys applied */
override string GetConfigFileName();
/* Static resolvers: read the active module's configuration, or fall back. */
static bool TryResolveActiveSDF(...);
static bool TryResolveBlinkRates(out float cursorRate, out float textRate);
static bool TryResolveDefaultLineHeight(out float lineHeight);
static bool TryResolveEffectSettings(out bool enabled, out float speed,
out int maxConcurrent, out bool reduceMotion);
static bool TryResolveThemeSettings(out string themeName, out bool applyToViews,
out bool remapOnChange);
}
See the API reference for full signatures, remarks, and exception contracts on every member.
Best Practices
- Create the asset when you want to ship, not before. The runtime default is fine while you are building; the asset earns its place when you need the config file mirror or a non-default theme at startup.
- Put the asset where the module can find it. Assign it on the module, or place it in
Resourcesunder the framework’s config folder so the module picks it up without an Inspector reference. - Treat the Grid group as starting values, not as a policy. Views override them freely, so a value here does not guarantee what a particular view will use.
- Leave SDF Threshold alone unless you know why you are moving it. Smoothing is the dial for sharpness; Threshold changes stroke weight and is usually the wrong tool for a text-looks-wrong problem.
- Cap Max Concurrent Effects to something you have tested. The default of 16 is generous. A lower cap turns a runaway caller into a refused play rather than a frame-rate problem.
- Prefer Reduce Motion to removing effects. It keeps the effect calls in your code and lets the module decide, which means the preference works everywhere rather than only where you remembered to check.
- Leave Publish Character Events off until something listens. It is one event dispatch per revealed character, which is real cost on a long paragraph for nothing if no handler exists.
- Use the static resolvers rather than passing the module around. They degrade gracefully in scenes without a bootstrap, which makes components easier to test in isolation.
- Export a config file as part of your build. Even if nobody edits it, having one next to the application means a support conversation can start from concrete values.
- Reset deliberately after a framework update. Serialized assets keep their old values, so new defaults do not arrive on their own.