dev:scriptref:start

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.

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.

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";

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: and npm: 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 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.

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.

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.

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

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

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 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).

GmcpTree · gmcp · ready · closed

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

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

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

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

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

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.

get