Everything Mudlet, TinTin++ and MUSHclient give you — triggers, aliases, timers, scripting, speedwalk, split windows, logging — built into the browser, with nothing to install and nothing to configure. Your setup follows your account, not your machine. This page is all of it, with the exact syntax and the traps worth knowing.
More about THOMAS → An illustrated tour of the platform this client is part of — the engine, the world editors and the VINE graph tools the game is built with.
stop that reaches all of it.Fire commands when a line of game text matches. Type trigger alone to list what you have.
trigger [@channel] [#group] [once] [Nln] <pattern> = <commands>
trigger off <pattern> remove that one
trigger on <pattern> re-enable a disabled one
trigger on|off #group disable/enable a whole group (never deletes)
trigger on|off all
trigger you're bleeding = bandage
trigger /^(\w+) hits you/ = flee
trigger @loot pipe = take pipe
trigger #combat you're hit = flee
trigger off #combat
trigger once /the safe clicks/ = open safe
trigger 3ln /the door opens.+inside/ = look
trigger you're bleeding = gag;say I saw that
| Piece | Meaning |
|---|---|
/…/ | Regex. Anything not wrapped in slashes is a case-insensitive substring — the default you can't write wrongly. |
$1–$9 | Regex captures, substituted into the command text. An absent group becomes empty, never the literal $3. |
@channel | Scope to a semantic message class — @say, @loot, @combat, @death… (~30 of them). An empty pattern plus a channel matches every line on it. |
#group | A label you can switch on and off as a set. Not part of the rule's identity, so regrouping moves a rule rather than duplicating it. |
once | Fires, then retires itself from storage — it won't come back after a reload. |
Nln | Multi-line, 1–10. Joins the last N lines and matches across them; regexes compile dot-all so . spans the join. Fires once per window, not once per line. |
@ and not colour. Other clients let you trigger on ANSI colour.
THOMAS has no ANSI — it has ~30 semantic classes on every line, and colour was
always a lossy proxy for exactly those. Colour triggers are deliberately never coming.trigger on all once the pattern is fixed.A trigger whose action is gag hides the matching line.
trigger you're bleeding = gag
trigger @say Vex = gag;say heard you
Gagging is resolved when the trigger is compiled, not while the script runs, and the line is suppressed before it's mounted rather than removed afterwards. That's what makes the find bar, the scrollback cap and Read Aloud all agree without any of them knowing gagging exists.
.savelog.The half text triggers can't reach: rules on your HP, thirst, sanity and the rest.
on list state rules
on hp_pct < 30 = drink stim
on thirst < 20 = drink water
on clear (also: on off)
The condition is a full expression (see §8) and is checked whenever your vitals update.
timer list
timer 30s = look repeating
timer 500ms = look
timer 5m = say still here
timer after 90s = say I have to go ONE-SHOT
timer off stop them all, and stay off
timer clear delete them all
Bare numbers mean seconds. The floor is 1s — anything faster is a command every tick, forever. A one-shot retires itself from storage when it fires, so it doesn't return on the next reload and go off half an hour later with nothing to explain it.
alias list
alias hb = say hello there
alias /^k (.+)$/ = attack $1
alias off k
alias on|off all
Same grammar as triggers. An alias may expand into a ;-chained script, and into client
verbs — alias f = macro fight works, because expansion feeds the macro runner.
Order of processing on submit: alias → speedwalk → stacking → client verb → server.
vars list all as $name = value
vars count read one
vars count 0 set (the value is an expression)
vars clear
Inside a script, use the segments set <name> <expr> and unset <name>.
Setting a variable skips the inter-command pacing and touches no network.
$hp always means hit points.
An unset variable fails every comparison rather than reading as zero.Press + on the smartbar to open the macro manager. A macro is a named script;
segments are split on newlines or ; and run top to bottom with a 350 ms stagger between
real commands.
| Segment | Does |
|---|---|
<command> | Any real command, routed exactly as if typed — including client-only verbs. |
delay <ms> | Pause. |
echo <text> | A local-only line in your log. |
$value | Live player values, interpolated. |
if / elseif / else / endif | Nestable. endif required. |
while / endwhile | Nestable. break and continue hit the innermost loop. |
macro <name> [args…] | Call another macro. Args bind $1–$9; $0 is all of them joined. |
set / unset | Variables. |
return [expr] | Ends this macro; the value lands in $result for the caller. |
wait for <pattern> [timeout] | Park until a line matches. See §9. |
gps clone facility
delay 500
auto on
while notin clone facility
delay 1500
endwhile
drink sink
attack enforcer
wait for /^(\w+) collapses/ 30s
loot $1
$values$hp $hp_max $hp_pct $stamina $sta $stamina_pct $sanity $sanity_pct $hunger $thirst
$radiation $rad $credits $horniness $body_temp $zone $zone_id $home $home_id
auto on or auto off — never bare
auto. Bare auto is a toggle, so its effect depends on state you can't see
from inside the script. And $home is a label, not a destination: use the
home verb, since gps matches names rather than ids.1000 steps per run · 20 levels of nesting · cycle detection on macro calls · a
1 second floor on any while pass that ran no delay of its own · and
a server-side token bucket that aborts your macros rather than disconnecting you.
Check & Fix normalises the script (one segment per line, lowercase keywords,
else if→elseif, =<→<=, appends a
missing endif, re-indents) and then validates — it must pass before Save unlocks.
A while with no delay in its body gets a non-blocking amber advisory.
The 📖 Guide tab lists your live values, the room's furniture actions, your items and the
verb list; clicking a row inserts it.
Conditions and set values are real expressions, not a fixed comparison shape.
if $hp_pct < 30 and has bandage
if $zone == bishops
if lower($1) contains enforcer
set trips $trips + 1
Precedence, loosest first: or · and · not ·
comparisons (< <= > >= == != contains starts ends) · + -
· * / · unary minus · has lacks in notin ·
parentheses. Functions: lower upper trim len word num round abs min max.
A bare word is a variable if one exists, otherwise its own text. Comparison is numeric when both
sides look numeric and case-insensitive string otherwise; + concatenates when either side
isn't a number.
has field bandage, lacks …,
in <zone>, notin <zone>. Nothing already written changed meaning.wait for — what makes a script a programwait for the door opens
wait for /^(\w+) collapses/ 30s
wait for /you're dead/ 500ms
Captures bind into the rest of the script, exactly as trigger captures do. A miss leaves
$result empty, so a script can branch on whether it actually landed. Parked scripts are
woken before triggers are considered, and every matching waiter wakes, not just the first.
stop cannot
reach a runner that isn't on a step boundary.Only wait for … is claimed — a bare wait still belongs to the game.
A red ■ Stop chip pins itself to the left of the smartbar whenever anything is running. Or type:
stop
In order: cancels auto-walk, aborts macros, switches timers off and persisted, and gives up
every parked wait for. If none of those were active it falls through to the game's own
stop. Timers are persisted off deliberately — a stop that leaves the
thing which restarts the automation running reads as broken.
Each macro can claim one key: F1–F9 or a numpad digit. It fires while your caret is in the command box, and is suppressed while a panel owns the keyboard (flight sim, cockpit, hangar, cab, piano) or at the login screen. One key, one macro — claiming releases the previous holder, and the manager shows you who that was.
The smartbar reads [+] [Tablet] [Inv] then your macro buttons then the room's context
verbs. Long-press ~350 ms to lift a button and drag it; the order is remembered per browser.
3n2e north north north east east
3ne northeast x3
2s1w
Expanded after aliases and run through the macro runner, so it paces itself room by room.
use — u, s and e are all directions, as are sew,
wed and dune. So 3n walks and nnn does not, and a
verb people type constantly is left alone. Cap is 40 steps; a zero count is refused.n;n;e three commands
say meet me at the bar; I'll be late NOT split
emote waves;; then bows NOT split; sends one ;
Free-text verbs (say, tell, whisper, emote) are
never split — the alternative is eating half of somebody's chat message. ;; anywhere
on the line escapes the whole line, and each ;; collapses to one ;.
Send matching lines to their own floating window. This is the "split windows" feature, and a route is just a trigger whose action is "put it over there" — so it reuses that grammar exactly.
route list
route @say = Chat a COPY; the line stays in the log
route @say = Chat only MOVES it out of the log
route /incoming/ = Combat
route off @say
route clear
Panes are draggable by the title bar, natively resizable, remember their position, hold 400 lines and follow their own tail.
route off <pattern> to actually stop routing.The other half of split windows — an input area that stays put while output scrolls — was never a gap here. The command box doesn't scroll.
highlight reactor core toggle one, default colour
hl reactor core same verb, shorter
highlight manager: colours and audible pings
highlight clear
find enforcer (or Ctrl+F)
.savelog write the transcript to a .txt
Highlights are plain substrings, never regex — a regex box in a field with no error surface throws on every line appended. Longest rule wins, one ping per line rather than per match, glyph art is skipped, and changing a rule repaints the log already on your screen. Find marks matches in place; step them with Enter / Shift+Enter.
.savelog reads a 20,000-line session buffer, not the screen.
The on-screen scrollback is trimmed as you play, so reading the document would start your transcript
wherever trimming had got to — which is exactly the part you saved it to read. The saved file's own
header states the limits and how many lines fell off the front. Gagged lines are included.Tab completes the first token against the live verb list (sent by the server
once per session from its real registries — never a stale hand-written list) and anything after it
against the nouns actually in the room. It fills the common prefix first, then cycles;
Shift+Tab walks back; candidates are sorted shortest-first so take
is reachable before takeoff. No match does nothing at all — it never invents a word,
and it never traps your Tab key.
Scroll back and the log stops following; an "N new lines ↓" chip takes you to the bottom. Entering a command also releases the lock. New lines, room changes and panels do not.
accessibility voice off
accessibility voice review fills the box, you press Enter
accessibility voice auto-send
Off by default — a player who never asks for a microphone is never asked for one. Tap the mic button, hold it to talk, or press Ctrl/Cmd+Shift+M from anywhere including inside the command box. (A chord, because the flight sim, the piano and WASD own the bare letter rows.) Firefox has no speech recognition and the button simply doesn't appear there.
The feature isn't the speech API — it's the normalizer. General speech recognition is trained
on prose and this game's input is jargon, so "wield rusty pipe" comes back "field rusty pipe" and a bare
n comes back "in". Three rules: aggressive on one token, cautious on many (a lone
"in" becomes n; the same word inside "put the coat in the locker" is untouched); the
vocabulary is live, scraped from what the room and your inventory are actually showing; and never
invent — unmatched speech passes through so the server answers Unknown command,
because a guess that lands on a real verb runs it.
drop, give, sell, buy,
pay, attack, quit and the consumables are never auto-sent,
whatever the mode says.accessibility read off
accessibility read natural the browser's own voice - recommended
accessibility read in-world the game's formant synth
accessibility speed slow|normal|brisk
Off by default, and deliberately so: the log is a live region, so a screen reader is already reading it — on by default would speak every line twice in two voices. Natural is recommended over the in-world synth, which fits the fiction but is harder work to listen to for an hour.
It rides the UI audio channel, so muting the television doesn't stop the game being read to you (the master Sound switch still does). Its queue is capped and drops the oldest — a voice minutes behind the game is describing a fight that already finished. Glyph art is never read. Entering a command interrupts it; Escape stops it dead.
accessibility list everything with current values
access alias
a11y alias
accessibility text large by label
accessibility text 19 by value
accessibility font read a unique prefix works
accessibility reset
| Verb | Setting | Options |
|---|---|---|
text | Text Size | Small / Medium / Large / X-Large … up to 200% |
font | Typeface | Monospace / Sans / Readable |
motion | Motion | On / Off |
marks | Status Marks | Off / On |
read | Read Aloud | Off / Natural / In-world |
speed | Reading Speed | Slow / Normal / Brisk … |
voice | Voice Input | Off / Review / Auto-send |
mono | Mono Audio | Off / On |
sfx | Sound Detail | Off / Limited / Full |
The tablet's Accessibility page and this verb render from the same table; neither owns it. The verb exists as a verb on purpose: it needs no tablet and prints straight into the log, so the setting stays reachable when the interface is not.
displaymode visual
displaymode textgames
displaymode log
Also settable before you log in, from the "Playing with a screen reader?" panel on the auth screen. Unlike everything above, this is server-side and follows your character.
| Rung | Minigames | Info panels | For |
|---|---|---|---|
visual | graphical | graphical | the default |
textgames | character-drawn, real-time, reflex intact | still graphical | wants text, keeps the games |
log | resolved by dice, not rendered | written into the scrolling log | screen readers |
At the log rung the area pane goes away, room descriptions reach the log, and arrivals
are abbreviated — but the classic MUD contract holds: nothing is ever lost, only deferred by one
keystroke. An explicit look is always the full description.
Macros, triggers, aliases, timers, state rules, highlights, variables and routes are all stored server-side against your character. Log in on another machine and they're there. There's nothing to export and no config file to copy.
Not synced, on purpose: the smartbar drag order, and every device-level preference — volume, theme, text size, and therefore all the accessibility options. A phone and a desktop shouldn't have to agree about volume.
@channel is the semantic thing colour was standing in for, and a worse duplicate would be the mistake.wait for has a timeout. A parked script is indistinguishable from a hung client..savelog writes a session buffer on demand. Streaming needs a Chromium-only API.