Script API reference
Generated from smudgy v0.4.0 (smudgy-core.d.ts @ 3c804cdb8fa3, smudgy-mapper.d.ts @ cdf62b070a90, smudgy-params.d.ts @ 36bdd47232ed, smudgy-widgets.d.ts @ fef07a6b0601)
Every function and type available to smudgy scripts.
Writing scripts
Smudgy's built-in script editor suffices for simple scripts, but it is a work in progress and not a good fit for complex scripts. For those, an IDE is strongly suggested. Modules (script files in your Documents/smudgy/<server>/modules/ folder) and installable packages (which have Edit a copy and Open in explorer/finder/file manager helpers) are designed to be edited outside of smudgy.
Smudgy maintains a TypeScript project next to your scripts, so an editor with TypeScript support provides autocomplete, type checking, and surfaces most of this guide inline:
- VS Code: (recommended) TypeScript support is built in.
- Other editors: use a TypeScript language server such as typescript-language-server.
- AI coding tools (Claude Code, Codex, and similar) generally recognize TypeScript projects and will read the reference information found here through the TypeScript project itself.
Everything in this reference is also in your editor. The IntelliSense documentation shown when hovering a function or symbol matches these pages.
Reading this reference
The reference is organized by module:
| Module | Covers |
|---|---|
smudgy:core | Sessions & output · Lines & buffer · Events · Automations · Saved automations · Panes |
mapper (from smudgy:core) | The map: areas, rooms, exits, pathfinding |
smudgy:widgets | On-screen UI built from widget components |
smudgy:params | Install-time options for installed packages |
smudgy:state/gmcp | GMCP: structured data from the server (vitals, room, chat) |
Smudgy's API is exposed through regular JavaScript imports:
import { on, send, createTrigger, mapper } from "smudgy:core"; // on('sys:connected', _ => send('look')); import { createWidget, Column, Text } from "smudgy:widgets"; // createWidget('my-widget', <Column><Text>My widget</Text></Column>); import { get } from "smudgy:params";
The runtime (Deno)
Scripts run on Deno. The language is stock JavaScript/TypeScript: strings, dates, JSON, and regular expressions are documented on MDN rather than here. Besides the smudgy modules above, the standard web APIs are available (fetch, WebSocket, localStorage, timers, crypto), along with:
- Node.js built-ins, through
node:imports:import { appendFile } from "node:fs/promises"might help you log chat output to its own file. - JSR and npm packages, through
jsr:andnpm:imports. For example, a smudgy module could post to a Discord channel with discord.js:
import { Client } from "npm:discord.js"; const client = Client({ intents: [] }); await client.login("your-bot-token"); const channel = await client.channels.fetch("your-discord-channel-id"); await channel.send("My smudgy script just sent this!");
Web workers (Worker) are not supported.
SQLite is built in: the node:sqlite module provides an embedded SQL database: import { DatabaseSync } from "node:sqlite". new DatabaseSync(getDataDir() + "/my.db") opens (or creates) a database file in the script's data directory.
In a sandboxed package, all of this obeys the manifest: e.g. network APIs need a network permission, and file-backed APIs need file permissions, etc.
Modules vs packages
Modules are loose script files in Documents/smudgy/<server>/modules/. Every file at the top level of that folder loads automatically in each session for that server; there is nothing to register or enable.
Packages are folders with a manifest (smudgy.package.json) and an entry module (index.ts by default), created and managed in the packages window; the files live in Documents/smudgy/<server>/packages/<name>/. A package loads through its entry module when enabled. Packages are versioned, can depend on other packages, ask for options at install time, and can be published for others to install. An installed package runs limited to the permissions its manifest declares, so what it can do (send commands, touch files, use the network) is visible before others install it.
Sharing packages
A published package has an address: smudgy://<owner>/<name>, where the owner is the publisher's smudgy.org nickname (created in-client, requires email validation). Publish from the packages window; each publish creates a new version, and published versions never change.
A package can be local (only on your device), private (hosted by smudgy, but only you and those you've shared it with can see and install it) or public (listed in Discover for anyone to find and install).
A package can also tag the MUD hostnames it is written for (hosts in the manifest). Searching Discover from a session then shows universal packages and packages tagged for that MUD; packages tagged only for other MUDs are left out. Tagged packages get a ranking boost, so a niche MUD's packages are not buried under globally popular ones.
Install packages from the packages window: public packages are searchable in Discover, and private packages (your own, and those shared with you) appear under Private & Shared.
A module imports an installed package by its address. The bare address is the package's entry module; a subpath names a file inside it.
// After installing kapusniak's arctic-prompt package: import { send } from "smudgy:core"; import promptEvent from "smudgy:events/kapusniak/arctic-prompt"; promptEvent.on({ hp }) => { if (hp && hp < 100) send("quaff healing"); });
A package that imports another package must also list it in its manifest's dependencies, optionally with a version range (smudgy://kapusniak/arctic-prompt@^1.0). Installing a package installs its dependencies with it.
Sandboxing
Smudgy Modules run with no sandbox: they are your own files, and nothing they do is restricted.
Every package, installed or locally authored, does run in its own sandbox, limited to the permissions its manifest declares. A call outside those permissions fails. The permissions are part of the manifest, so they are shown before anything runs; a package can never quietly do more than what you've explicitly agreed to.
If a package publishes a version which requires more permissions, updates to that version for existing installations will be blocked until they approve the new permissions.
The permissions a package can request:
| Permission | What it allows |
|---|---|
| Send commands | Can send text to the game as if the user typed it; possibly being re-triggered by other aliases in different sandboxes |
| Send commands directly | Can send text to the game directly, does not interact with other scripts |
| Echo text | Writing lines to its session's terminal |
| Terminal Display | line.gag()/highlight/replace, interacts with Panes to offer line.redirect(pane) and line.copy(pane) |
| Aliases | Can create and manage its own aliases in an isolated namespace |
| Triggers | Can create and manage its own triggers in an isolated namespace |
| Interact with other sessions | Exposes sessions, allows interacting with other sessions, e.g., sessions[X].send('hi')) |
| Read your maps | Read access to all maps, rooms, exits, and metadata |
| Change your maps | Write access to all maps, rooms, exits, and metadata |
| Widgets | Create or update widgets |
| Panes | Can split the session's terminal into multiple panes and route game lines into them |
| Broadcast events | Emitting events other packages can hear, under its own name |
| Listen for events | Subscribing to smudgy's events and other packages' events |
| Network access | Can only reach specific hosts it lists. Applies to both incoming and outgoing connections. |
| Read files | Lists folders/files it can read, $DATA is expanded to the package's private data directory |
| Write files | Lists folders/files it can write, $DATA is expanded to the package's private data directory |
| Environment variables | Can only read the specific variables it lists |
| Import code | import from npm, jsr, or other external sources |
Some abilities cannot be declared at all: a sandboxed package can never start other programs or load native libraries, no matter what its manifest asks for, though this is subject to change.
What a sandbox is: each sandboxed package runs in its own V8 isolate, a separate instance of the JavaScript engine with its own memory and globals. Isolates share nothing, so a package cannot reach the variables of your modules or of any other package. Chrome uses the same mechanism: the JavaScript of each browser tab and each web worker runs in its own isolate, which is why one page's scripts can never touch another's.
With Enable advanced scripting features turned on in the preferences window, a package can be trusted from the packages window. A trusted package's sandbox is removed entirely. It runs with the same full access as your modules, in the same isolate. Trust is per package and off by default.
smudgy:core — Sessions & output
The basic output functions (echo/send/sendRaw), the current session and other connected sessions, and the profile and app settings. Import from smudgy:core.
echo · send · sendRaw · reload · session · id · Session · getSessions · byName · getProfile · Profile · getSettings · Settings · Palette · getDataDir · vars · mapper · SmudgyApi
smudgy:core — Lines & buffer
Read and edit the text on screen: the line a trigger is processing right now (line), recently printed lines (buffer), colors and styling, and alias capture control.
line · buffer · Line · Buffer · capture · style · link · StyledText · StyleBuilder · StyleTag · LinkClick · Color · StyleSpan · LineColorOptions
smudgy:core — Shared state & events
Scripts and packages share live data through three kinds of handles: states, events, and procedures. A state holds a value other scripts can read at any time, such as your hp or a roster of group members. Consumers can also watch a state for changes, or bind a widget property to one of its entries; a health bar bound to an hp entry repaints whenever the value changes, without any script running.
An event is a notification that something happened, delivered to every subscriber. Handling one with on() is much like handling a matching line with a trigger, with another package as the source instead of incoming text. Smudgy's own events are delivered the same way: smudgy:events/sys and smudgy:events/map announce connection and disconnection, sent commands, received lines, and map movement. A procedure is a function one package implements and other packages can call; a script might use one to ask a mapper package to start a speedwalk.
Packages declare their own handles with createState, createEvent, and createProcedure, and use another package's with an ordinary import.
createState · createEvent · createProcedure · createDerived · StateHandle · EventHandle · ProcedureHandle · DerivedHandle · StateConsumer · EventConsumer · ProcedureConsumer · ConsumerOf · Payload · EventSubscription · StatePath · StateAt · Binding · BindOptions · events · connect · disconnect · send · receive · room
GMCP
GMCP is a data channel many MUDs run alongside the text you see: the server sends structured messages (vitals, room details, chat lines) that scripts read directly instead of parsing the screen. Smudgy negotiates it automatically and collects everything the server has sent into one live tree, consumed like any shared state (events).
smudgy:core — Automations
Aliases, triggers, timers, and hotkeys created from scripts: the create* functions, the handles they return, and the registries. These are cleared and recreated on every script reload. For the saved automations shown in the automations window, see saved-automations.
createAlias · createTrigger · createTriggers · createTimer · createHotkey · Alias · Trigger · Timer · Hotkey · aliases · triggers · timers · hotkeys · AutomationRegistry · Matches · InlineTemplate · TriggerPatterns · TriggerDef · AliasOptions · TriggerOptions · TimerOptions · HotkeyOptions · KeySpec
smudgy:core — Saved automations
Create, edit, and delete the saved aliases/triggers/hotkeys (the ones shown in the automations window) from a script, via userAutomations. Saved automations run outside any sandbox, so they are not available to sandboxed packages: writing one would let the package run code outside its sandbox. For the automations scripts create with the create* functions, see automations.
userAutomations · UserAutomations · SavedAutomationRegistry · SavedAutomationHandle · SavedAlias · SavedTrigger · SavedHotkey · SavedAliasHandle · SavedTriggerHandle · SavedHotkeyHandle · ScriptLang
smudgy:core — Panes
Session panes: split named panes off the main pane (or off each other) and write lines into them. Panes host widgets (see widgets) and, unless created widgets-only, a terminal.
Pane · PaneRegistry · PaneRegistryMethods · PaneSpec · PaneSpecBase · SplitDirection · TitleBarSpec
smudgy:widgets
Script-driven UI: build widget trees from the components below (directly or with JSX in a .tsx module) and put them on screen with createWidget. Import from smudgy:widgets.
createWidget · removeWidget · CreateWidgetOptions · Column · ColumnProps · Row · RowProps · Stack · StackProps · Container · ContainerProps · Text · TextProps · ProgressBar · ProgressBarProps · Button · ButtonProps · ButtonVariant · Scrollable · ScrollableProps · ScrollDirection · Markdown · MarkdownProps · Modal · ModalProps · TextEditor · TextEditorProps · MapView · MapViewProps · extractMarkdownLinks · MarkdownLink · Element · Length · Children · Bindable · HorizontalAlign · VerticalAlign · SmudgyElement · WidgetLength · WidgetChild · WidgetChildren · jsx · jsxs · Fragment · JSX
Mapper
The map API: import { mapper } from "smudgy:core". The map types (Area, Room, …) need no import.
mapper · Mapper · Area · Room · Exit · CreateRoomParams · UpdateRoomParams · ExitArgs · ExitUpdates · AreaJson · Label · LabelArgs · LabelUpdates · Shape · ShapeArgs · ShapeUpdates · AreaId · RoomNumber · ExitId · LabelId · ShapeId · ExitDirection · ExitStyle · LabelHorizontalAlign · LabelVerticalAlign · ShapeKind
smudgy:params
Per-package configuration: read the option values chosen when a package was installed (the options block of its smudgy.package.json). Import from smudgy:params.