SyncTERM themes are INI files which define user-interface styles and glyphs. The C host loads one theme for the process and exposes immutable snapshots of it to the menu, file-picker, and connected Wren VMs. All three VMs therefore start with the same program-wide theme.

Storage and Selection

Theme files use the .ini extension and live in the per-user themes directory beside the per-user scripts directory. The exact path is shown by SyncTERM SettingsFile Locations. Typical locations are:

Platform Directory

Windows

%APPDATA%\SyncTERM\themes\

macOS

~/Library/Application Support/SyncTERM/themes/

Unix

$XDG_DATA_HOME/syncterm/themes/, normally ~/.local/share/syncterm/themes/

Haiku

The user’s settings directory followed by SyncTERM/themes/

The selected basename is stored as ThemeFile in the [SyncTERM] section of syncterm.ini. Paths are not accepted. A theme installed from the online catalog is instead stored as ThemePackage, using a stable identifier such as official/dark-mode. ThemeFile and ThemePackage are mutually exclusive. Selecting the built-in Classic Theme removes both keys instead of storing a special name.

At startup, a missing or invalid selected file or cached package falls back to Classic Theme without deleting the configured identity. The appropriate theme browser displays that selection as invalid so it can be diagnosed after the file or package is restored. The browser previews valid themes as the highlight moves, saves a selection on Enter, and restores the committed theme on Escape. Invalid entries remain highlightable for their error text but cannot be selected.

The six settings under [ClassicTheme] affect only the built-in Classic Theme. A file theme is a sparse overlay on SyncTERM’s compiled default and does not inherit those six colour preferences.

Online Themes

The Themes browser lists the built-in Classic Theme, local theme files, and packages which have been downloaded into the cache. F6 opens Online Themes, which lists only manifest packages without a cached copy. Enter downloads and selects an online package, F2 downloads it as an unsaved local copy in the theme editor, and F5 refreshes the manifest and downloaded packages. Cloud packages are read-only cache entries; editing one creates an ordinary file in the per-user themes directory which is no longer associated with manifest updates. Both browsers show the highlighted theme’s Description on the main-screen comment line. Delete removes a local theme file or cached package; deleting the selected theme first selects Classic Theme. A deleted cached package returns to Online Themes.

The official manifest and its packages are stored below syncterm-system-cache/themes/official in SyncTERM’s cache directory. This keeps automatically managed files separate from manually installed themes. Files ending in .download are HTTP cache bodies. SyncTERM promotes a body to manifest.lst or <id>.ini only after validation, so an invalid response does not replace the last accepted copy. Clearing the system cache removes downloaded packages but does not remove ThemePackage from syncterm.ini. SyncTERM falls back to Classic until that package is available again.

Once an online catalog has been used, SyncTERM checks it during startup. Packages already present in the cache, including the selected package, are updated when their manifest SHA-256 changes. Entering the Online Themes browser also checks for updates. A network or validation failure retains the previous validated package and is shown in the browser.

The official catalog is read from http://syncterm.bbsdev.net/themes/manifest.lst. Its contents use INI syntax:

Repository = official
Name = SyncTERM Themes

[Theme:dark-mode]
Name = Dark Mode
Author = Example Author
Description = A dark theme
Version = 1.0
URI = http://syncterm.bbsdev.net/themes/dark-mode.ini
SHA256 = 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef

Repository must occur exactly once and currently must be official. Section suffixes are stable package IDs containing only lowercase ASCII letters, digits, periods, underscores, and hyphens. Name, an absolute HTTP or HTTPS URI, and a 64-digit SHA256 are required. Author, Description, and Version are optional. Duplicate package sections or duplicate recognized fields make the complete manifest invalid. The SHA-256 identifies the exact theme file bytes; after the hash matches, the normal theme loader must also accept the file before it can be installed.

Classic Extended

Classic Extended retains the default Classic Theme’s legacy 16-colour attributes role for role. On RGB-capable backends it expands the familiar blue, cyan, yellow, grey, and red scheme with additional shades for focused, inactive, input, status, help, log, and popup roles.

Official Colour-Vision Themes

The official catalog includes ten palettes for colour-vision conditions. Each theme defines every built-in style in both RGB and legacy 16-colour form. Legacy attributes keep bit 7 clear, so they do not request blinking text on VGA-compatible backends. Focus, inactive, disabled, input, status, warning, and popup states are reinforced by luminance or reversal rather than hue alone.

Condition Theme

Protanomaly

Emberworn

Protanopia

Emberless

Deuteranomaly

Verdantworn

Deuteranopia

Verdantless

Tritanomaly

Azureworn

Tritanopia

Azureless

Red-cone monochromacy

Crimsonbound

Green-cone monochromacy

Viridianbound

Blue-cone monochromacy

Ceruleanbound

Achromatopsia

Ashen

Theme Editor

The Themes browser accepts Insert to create a theme and F2 to edit the highlighted theme. New themes begin as minimal sparse overlays on the compiled default. The built-in Classic Theme cannot be modified in place; editing it creates an unsaved copy which must be given a filename. A file which is not accepted by the current theme loader remains visible in the browser for diagnosis, but cannot be selected or opened in the editor.

The editor’s atlas contains every style role and glyph in the draft. Show Glyphs / Show Styles changes the kind of definition shown. Show Legacy / Show RGB changes the style colour display, and Show ASCII / Show CP437 changes the glyph display; the title reports the active mode. CP437 mode shows each glyph with its hexadecimal byte value, while ASCII mode shows the printable fallback and its decimal value. Preview opens an interactive screen of real menu, list, form, input, selection, button, progress, and status widgets using the unsaved draft theme. The preview’s outer frame retains the installed theme so it remains usable even when the draft is incomplete or unreadable. Its status line identifies the role used by the focused widget; F2 closes the preview and selects that role in the atlas. The inspector shows each resolved style field and the role which supplied it. Cascade shows every role considered for all four fields, including absent and inherited entries and the winning source. Enter or a double click edits the selected definition; Insert creates a custom definition and Delete removes one.

A built-in style field has three possible states:

  • Default removes the file’s value and uses the compiled value for that role. A compiled inherit value continues through the role cascade.

  • Inherit writes inherit and explicitly continues through the role cascade.

  • Explicit stores the selected value in the theme file.

Built-in glyph fields support Default and Explicit. CP437 values are selected from a 16 by 16 grid of all byte values. ASCII fallbacks are selected from a 16 by 6 grid containing space through tilde. The raw CP437 grid always uses font slot 0 so a draft style’s font cannot change the meaning of the cells. Arrow and page keys wrap through each grid; Enter or double click accepts and Escape cancels. Custom style and glyph definitions are stored in full and can be removed. Metadata edits the global Name, Author, Description, and Version values.

Import replaces all style and glyph sections with those from another theme as one undoable operation. This includes custom definitions, comments, ordering, and unknown fields in those sections. The destination filename and global metadata are retained. Importing Classic Theme synthesizes its current complete set of definitions.

Undo and Redo apply only to the current editing session. Save writes without closing the editor and starts a new undo session. Save As accepts a basename in the themes directory; paths are not accepted. Closing a dirty document asks whether to save, discard, or continue editing. Safe mode permits browsing but does not permit saving.

The editor preserves comments, ordering, unrecognized metadata, unrecognized sections, and unmodified values from an opened file. Values changed through the editor are rewritten in the normal theme syntax. Before replacing an opened file, Save compares its source lines with the lines originally read and asks before overwriting an external change. New destinations also require confirmation before replacement. The completed output is parsed and validated before an atomic replacement is attempted.

File Structure

Metadata is written before any section header:

Name = Example Theme
Author = Example Author
Description = A short description shown in the Themes browser
Version = 1.0

[Style:default]
Foreground = 0xFFFFFF
Background = 0x000040

[Style:list.item.focused]
LegacyAttr = 0x70
Foreground = 0x000000
Background = 0xC0C0C0

[Glyph:scrollbar.thumb]
CP437 = 219
ASCII = 35

Name is required and must not be empty. Author, Description, and Version are optional. Duplicate recognized metadata keys are errors. Unrecognized metadata, sections, and keys are ignored for forward compatibility.

Recognized section names and keys are case-insensitive. Two recognized sections with the same name, including names which differ only in case, make the file invalid. A malformed value or duplicate recognized key also makes the file invalid.

Styles

A [Style:role] section may contain these fields:

Field Range Meaning

Font

0..255

Conio font slot.

LegacyAttr

0..255

IBM text attribute used by legacy-colour backends.

Foreground

0..0xFFFFFF

24-bit RGB foreground used by RGB-capable backends.

Background

0..0xFFFFFF

24-bit RGB background used by RGB-capable backends.

Numbers use C integer syntax, so decimal and 0x hexadecimal forms are accepted. The case-insensitive value inherit clears a field and makes it inherit through the Wren role cascade. Omitted fields retain the compiled default value for an existing role; a new role starts with all fields set to inherit.

Role lookup removes dotted suffixes until it reaches default. For example, list.item.focused falls back through list.item, list, and default. Roles ending in .inactive use the parallel inactive cascade before falling back to default. The resulting default style must contain all four fields, so a file which clears one of its fields without replacing it is invalid.

The current role registry is:

Role Use

default, default.inactive

Cascade terminators and general screen/pane colours.

frame, frame.inactive

Pane and dialog borders.

title, title.inactive

Pane and dialog border titles.

menu.item, menu.item.focused, menu.item.disabled

Command-menu rows.

list.item, list.item.focused, list.item.disabled, list.item.focused.inactive

List rows, including the selected row in an unfocused pane.

input, input.focused

Text-input fields.

button, button.hotkey, button.focused, button.focused.hotkey

Button labels and their shortcut character.

statusbar

Status and help bars.

checkbox, checkbox.focused

Check-box controls.

radio.item, radio.item.focused

Radio-button rows.

spinbox, spinbox.focused

Numeric spin controls.

menubar, menubar.item, menubar.item.focused

Menu bars and their entries.

scrollbar.track, scrollbar.thumb

Scrollbar track and position indicator.

progress.fill

Filled portion of a progress bar.

logview.info, logview.notice, logview.warning, logview.error

Transfer and diagnostic log severities.

help, help.text, help.bold, help.code, help.heading.1, help.heading.2, help.heading.3, help.bullet

Markdown help content.

popup, popup.frame, popup.frame.inactive

Status and alert popups.

classic.backdrop, classic.header, classic.console, classic.console.error, classic.comment, classic.hint, classic.hotkey

Main-menu screen chrome. These roles are optional in file themes and otherwise cascade to default.

Scripts may use additional role names. A theme file may style such a role before it becomes part of the built-in registry.

Glyphs

A [Glyph:name] section uses numeric byte values:

  • CP437 is 0..255 and identifies the primary CP437 glyph.

  • ASCII is a printable ASCII byte, 32..126, used when the primary glyph cannot be rendered.

Literal characters are not accepted because many CP437 glyphs are control codes, whitespace, or not representable in the theme file’s encoding. An existing glyph may override either value. A new glyph name must provide both CP437 and ASCII.

The built-in glyph registry is:

Name CP437 ASCII

background

32

32

frame.display.topLeft

218

43

frame.display.top

196

45

frame.display.topRight

191

43

frame.display.left

179

124

frame.display.right

179

124

frame.display.bottomLeft

192

43

frame.display.bottom

196

45

frame.display.bottomRight

217

43

frame.display.tee.left

195

43

frame.display.tee.right

180

43

frame.display.title.left

180

45

frame.display.title.right

195

45

frame.display.tee.top

194

43

frame.display.tee.bottom

193

43

frame.display.cross

197

43

frame.display.separator

196

45

frame.control.topLeft

201

43

frame.control.top

205

61

frame.control.topRight

187

43

frame.control.left

186

124

frame.control.right

186

124

frame.control.bottomLeft

200

43

frame.control.bottom

205

61

frame.control.bottomRight

188

43

frame.control.tee.left

204

43

frame.control.tee.right

185

43

frame.control.title.left

181

61

frame.control.title.right

198

61

frame.control.tee.top

203

43

frame.control.tee.bottom

202

43

frame.control.cross

206

43

frame.control.separator

205

61

scrollbar.track

176

58

scrollbar.thumb

219

35

scrollbar.up

30

94

scrollbar.down

31

118

scrollbar.separator

179

124

arrow.up

24

94

arrow.down

25

118

arrow.right

16

62

arrow.left

17

60

focus.left

16

62

focus.right

17

60

check.on

251

88

check.off

32

32

radio.on

7

42

radio.off

9

111

tag.on

175

62

tag.off

32

32

Scripts may define and use additional glyph names, subject to the requirement that a new name supplies both byte values.

Compatibility

The role and glyph registries may grow as UI widgets are added. Unknown content is ignored so a file can include entries understood by newer SyncTERM versions, while sparse overlays automatically receive new compiled defaults. Theme authors should still test both RGB and legacy-colour output, because every visible style can be rendered through either representation.