Styled object text
Object names, descriptions, and inside descriptions support a small, declarative markup language. It replaces the old dependency on softcode color escapes without restoring softcode evaluation; OSC link actions occur only when a user activates a rendered link.
@name drone=[fg=bright-cyan]Aegis[/]
@desc drone=A shell of [fg=#d78700]burnished amber[/] metal.
@idesc dropship=[fg=#8090ff bold]Cool blue light[/] fills the cabin.
Syntax
[color=COLOR] changes the foreground; the existing fg name remains an
alias. [bg=COLOR] changes the background.
[bold], [blink], [underline], and [inverse] enable formatting. Multiple
directives can share one tag when separated by whitespace, for example
[fg=blue bg=white bold]. A grouped tag creates one style scope, so one [/]
restores every setting that it changed. [reset] restores terminal defaults
and closes all open styles. Use [[ for a literal opening bracket.
OSC 8 hyperlinks use the same scoped representation:
[link="https://example.com"]Website[/]
[send="look"]Look[/]
[prompt="cast fireball"]Prepare a spell[/]
[send="attack" color=red bold hover.color=yellow]Attack[/]
[link] accepts http:, https:, and ftp: URIs. Command targets are raw
UTF-8 text and are percent-encoded when rendered. Targets are double quoted;
escape a quote as \" and a backslash as \\. Formatting may be nested
inside a link, but links may not be nested.
Link-local visual properties share the opening link tag. The base properties
are color/fg, bg, bold, italic, underline, overline,
strikethrough, and text-decoration-color. Boolean values may be bare or
written as =true/=false; decorations also accept wavy, dotted, and
dashed. Repeated properties use the last value.
State-specific properties use dotted full names, such as
hover.color=yellow, active.bg=bright-red, or visited.bold=false. The
available states are active, hover, focus-visible, focus, visited,
selected, disabled, link, and any-link. Only properties on the link’s
opening tag become OSC JSON. Separately nested style tags remain ANSI scopes.
Tier 3 adds quoted tooltip and title text plus indexed context-menu fields:
[send="attack" tooltip="Choose an action" title="Combat" title.bold menu.1.label="Attack" menu.1.send="attack" menu.2.label="Inspect" menu.2.prompt="examine target" menu.3.separator menu.4.label="Guide" menu.4.link="https://example.com/guide"]Attack[/]
Menu indices begin at 1 and are contiguous. An entry is either
menu.N.separator or has a quoted menu.N.label and exactly one quoted
menu.N.send, menu.N.prompt, or menu.N.link action. Fields may appear in
any order. Title styling uses the base link properties with a title. prefix;
state-specific title styles are not supported. All quoted values use the same
\" and \\ escapes as link targets and must contain printable UTF-8.
Tier 4 adds dynamic visibility and behavior fields:
[send="look" visibility.action=conceal visibility.delay=500 visibility.expire.prompt visibility.wholeline]Dismiss[/]
[send="hint" visibility.action=reveal,conceal visibility.delay=3000]Hint[/]
[send="look" spoiler]Hidden answer[/]
[send="look" spoiler disabled]Reveal-only answer[/]
Visibility actions are conceal, reveal, and reveal,conceal. Delay and
visibility.expire.outputDelay values are unquoted unsigned millisecond
integers. Expiry triggers are visibility.expire.input,
visibility.expire.prompt, and visibility.expire.output; at least one must
be enabled when expiry fields are used. outputDelay requires output expiry.
visibility.wholeline, spoiler, and disabled use the standard bare or
explicit boolean syntax.
Tier 5 groups links into client-local selections:
[send="say difficulty hard" selection.group="difficulty" selection.value="hard" selection.exclusive selection.selected selected.bg=red selected.bold]Hard[/]
[send="say strength toggled" selection.group="buffs" selection.value="strength" selection.exclusive=false]Strength[/]
Quoted, non-empty selection.group and selection.value fields are required.
The optional boolean fields are selection.toggle, selection.selected,
selection.exclusive, and selection.disabled. Exclusive groups behave as
radio buttons; non-exclusive groups permit multiple selected values. Group
membership and uniqueness are maintained by each client console, not by the
server renderer.
Tier 6 adds reusable, globally configured presets:
[send="attack" preset="osc8-demo-danger"]Attack[/]
[send="repair" preset="osc8-demo-button" bg=blue tooltip="Repair armor"]Repair[/]
The quoted preset name is case-sensitive. Link-local directives recursively override the preset; a link-local menu replaces the preset menu as one array. Presets may be partial templates, but the merged link must meet the ordinary menu, visibility, selection, and title validation rules. Unsupported clients receive the merged configuration inline.
For accessible links, use a descriptive tooltip rather than relying on the raw command fallback, and choose selection group/value names that communicate their purpose to assistive technology.
Colors accept an opaque CSS/X11 name, exactly six hexadecimal digits in
#RRGGBB form, or rgb(RED,GREEN,BLUE) with integer channels from 0 through
255. The RGB function is case-insensitive but does not allow spaces,
percentages, or alpha channels. Game administrators can add case-insensitive
custom names in the [colors] table of stompymux.toml; configured colors use
[RED, GREEN, BLUE] integer arrays and may not overlap a built-in CSS/X11
name.
Built-in named colors
The following 148 opaque CSS/X11 color names are built in. Names are
case-insensitive; spellings such as gray/grey and aqua/cyan are aliases
with the same RGB value. transparent is not supported because styled-text
colors do not have an alpha channel.
aliceblue antiquewhite aqua aquamarine
azure beige bisque black
blanchedalmond blue blueviolet brown
burlywood cadetblue chartreuse chocolate
coral cornflowerblue cornsilk crimson
cyan darkblue darkcyan darkgoldenrod
darkgray darkgreen darkgrey darkkhaki
darkmagenta darkolivegreen darkorange darkorchid
darkred darksalmon darkseagreen darkslateblue
darkslategray darkslategrey darkturquoise darkviolet
deeppink deepskyblue dimgray dimgrey
dodgerblue firebrick floralwhite forestgreen
fuchsia gainsboro ghostwhite gold
goldenrod gray green greenyellow
grey honeydew hotpink indianred
indigo ivory khaki lavender
lavenderblush lawngreen lemonchiffon lightblue
lightcoral lightcyan lightgoldenrodyellow lightgray
lightgreen lightgrey lightpink lightsalmon
lightseagreen lightskyblue lightslategray lightslategrey
lightsteelblue lightyellow lime limegreen
linen magenta maroon mediumaquamarine
mediumblue mediumorchid mediumpurple mediumseagreen
mediumslateblue mediumspringgreen mediumturquoise mediumvioletred
midnightblue mintcream mistyrose moccasin
navajowhite navy oldlace olive
olivedrab orange orangered orchid
palegoldenrod palegreen paleturquoise palevioletred
papayawhip peachpuff peru pink
plum powderblue purple rebeccapurple
red rosybrown royalblue saddlebrown
salmon sandybrown seagreen seashell
sienna silver skyblue slateblue
slategray slategrey snow springgreen
steelblue tan teal thistle
tomato turquoise violet wheat
white whitesmoke yellow yellowgreen
BattleTech maps, status displays, menus, and notifications use this markup and the same named palette rather than maintaining a separate terminal-color path.
Markup is validated when a builder sets the value. Malformed tags and literal terminal escape sequences are rejected. The validated markup itself is stored in the database; terminal-specific ANSI is generated only when output is sent to a client.
Wizards see the markup form of the examined object’s name, description, and
inside description in @examine, so the exact stored value can be copied,
edited, and set again.
Player-authored say and page message bodies are plain text channels.
Styled markup and raw terminal escapes are stripped before those messages are
delivered. Styling on player names remains independent.
Client adaptation
The server discovers terminal capabilities with MTTS-over-TTYPE when the
client supports it. RGB colors are emitted directly for truecolor clients and
mapped to the nearest xterm-256 or ANSI-16 color for less capable clients.
The existing player ANSI flag remains the persistent opt-in. Plain clients
and clients reporting MTTS screen-reader mode receive text with formatting
removed.
Color depth is connection-specific, so separate sessions for one player may receive different ANSI color sequences. Text encoding is always UTF-8.
OSC support is also connection-specific, but is independent of color and
screen-reader selection. The server checks the OSC_HYPERLINKS,
OSC_HYPERLINKS_SEND, and OSC_HYPERLINKS_PROMPT NEW-ENVIRON USERVARs for an
exact 1 value. Unsupported link tags render as their visible contents without
OSC escape sequences.
Tier 2 uses the exact-1 USERVARs OSC_HYPERLINKS_STYLE_BASIC and
OSC_HYPERLINKS_STYLE_STATES. The renderer sends percent-encoded JSON with
full Mudlet property names for advertised features. Base styles otherwise use
ANSI fallback where possible, decoration variants reduce to their plain form,
and interactive states are omitted. OSC styling is capability-driven and
remains independent of the player’s ANSI preference; ANSI fallback continues
to respect that preference and the negotiated color depth.
Tier 3 uses OSC_HYPERLINKS_TOOLTIP and OSC_HYPERLINKS_MENU. The renderer
emits each feature only for an exact 1; menu entries are further filtered by
the web, send, and prompt scheme capabilities. Filtering removes leading,
trailing, and duplicate separators, and an empty menu also omits its title.
Title styling requires OSC_HYPERLINKS_STYLE_BASIC; otherwise the title is
sent without a style object. Tier 3 metadata has no ANSI or plain-text fallback.
Tier 4 uses the exact-1 USERVARs OSC_HYPERLINKS_VISIBILITY,
OSC_HYPERLINKS_SPOILER, and OSC_HYPERLINKS_DISABLED. Visibility supports
conceal, reveal, and reveal-then-conceal actions, optional millisecond delays,
input/prompt/output expiry triggers, and whole-line concealment. Spoilers hide
their text until activated, while disabled links block their action and menu.
Combining spoiler and disabled creates reveal-only content.
Unsupported visibility and spoiler configuration is omitted. If markup
requests disabled=true and the client does not advertise disabled-link
support, the renderer suppresses the OSC link and retains its visible text and
ANSI-compatible base styling. Visibility is intended for single-line links;
spoilers are a display effect rather than protection for confidential data.
When any Tier 2 through Tier 5 configuration capability or Tier 6 compact
capability is advertised, the
renderer percent-encodes an existing web query parameter named config so it
cannot be mistaken for Mudlet configuration.
Tier 5 uses the exact-1 OSC_HYPERLINKS_SELECTION USERVAR. Without it, the
selection object is omitted while the ordinary link remains active. Selection
behavior is independent of OSC_HYPERLINKS_STYLE_STATES, which separately
controls selected. and disabled. visual properties.
Mudlet adds or replaces a selected=true/selected=false query item on
activated send and prompt commands. Selection-enabled commands must reserve
that query name for the callback. Web links can retain client-local selection
state, but current Mudlet code leaves their URL unchanged. The specification’s
nested selection.disabled is emitted as written; some current Mudlet builds
do not consume it, so top-level Tier 4 disabled remains the choice for a
fully non-interactive link.
Tier 6 independently checks exact-1 OSC_HYPERLINKS_COMPACT and
OSC_HYPERLINKS_PRESETS USERVARs. Compact clients receive the documented
short property names with no semantic change. Preset-capable clients receive
the global definitions once per connection before the first subsequent normal
output, then links carry preset=NAME plus only their overrides. Definitions
and overrides use the same compact or full-name representation. An advertised
preset capability reserves an existing web preset query parameter.
The color command displays or overrides the current connection’s selection.
Use color auto for negotiation, color off for plain text, or color 16,
color 256, and color truecolor to force a depth for the current session.
This also provides an explicit opt-in for a screen-reader session. The
persistent player ANSI flag remains the outer control and must be enabled.