@urth/metatell-sdk is a TypeScript SDK for building third-party plugins that
run inside metatell. A plugin uses it to access user information, presence,
devices, screen sharing, the avatar, waypoints, chat, input, voice, emotes, room
objects, Spoke triggers, backgrounds, and metrics.
The SDK is published as ESM and is meant to run in the browser-side plugin runtime, not in Node.js.
At runtime the metatell host must provide window.MetatellPlugin and
window.APP. On a normal web page or in a Node.js process these objects do not
exist, so the SDK will not work there. Most getters return undefined or an
empty list when the host is not ready, so always null-check values such as
getProfile()?.displayName. The class-based APIs (Camera, Mic, Screen,
Avatar) and getWaypoints() access window.MetatellPlugin directly and throw
when it is missing.
npm install @urth/metatell-sdk
# or
pnpm add @urth/metatell-sdk
The root entry exposes the class-based and namespace APIs:
import { Avatar, Camera, Mic, Screen, metrics, user } from "@urth/metatell-sdk";
import { getWaypoints, warpToWaypoint } from "@urth/metatell-sdk";
Most function-based features are exposed under subpath imports, which keep bundles small and group related APIs:
import { getProfile } from "@urth/metatell-sdk/user";
import { list, onJoin } from "@urth/metatell-sdk/users";
import { send, onMessage } from "@urth/metatell-sdk/chat";
TypeScript types for the root-entry callbacks (TransformData, DeviceData,
WaypointData, …) are available from @urth/metatell-sdk/types/property.
| Import | What it covers | Guide |
|---|---|---|
@urth/metatell-sdk/user |
Self session/account id, profile, avatar id, movement | User Profile, User Movement |
@urth/metatell-sdk/users |
Other users in the room (presence) | Remote Users |
@urth/metatell-sdk/chat |
Send / receive chat, mentions | Chat |
@urth/metatell-sdk/input |
Pointer, hover, gaze, raycast | Input |
@urth/metatell-sdk/voice |
Local mic level, speaking state | Voice |
@urth/metatell-sdk/emote |
Trigger / observe emotes | Emote |
@urth/metatell-sdk/events |
Low-level typed event bus | Events |
@urth/metatell-sdk/objects |
Read, spawn, move, and pin room objects (experimental) | Room Objects |
@urth/metatell-sdk/triggers |
List, fire, and observe Spoke -2 triggers (experimental) |
Triggers |
@urth/metatell-sdk/auth |
Plugin API token exchange | Auth |
@urth/metatell-sdk/lifecycle |
Cleanup scopes, host runtime and room scopes | Resource lifecycle |
@urth/metatell-sdk/runtime |
Host capabilities, readiness, SdkError |
Runtime |
@urth/metatell-sdk/environment |
Personal and shared room backgrounds | Environment |
Avatar, user.changeAvatar |
Avatar transform + avatar id | Avatar |
Camera, Mic, Screen |
Media device callbacks | Media Devices |
metrics |
Analytics events | Metrics |
getWaypoints, warpToWaypoint |
Room waypoints | Waypoints |
Most "live" features are built on a typed event bus. Subscription functions —
their names start with on… — return an Unsubscribe function:
type Unsubscribe = () => void;
Always keep the returned function and call it when your plugin is torn down. Leaked subscriptions keep firing handlers against stale state.
import { onMessage } from "@urth/metatell-sdk/chat";
import { onJoin } from "@urth/metatell-sdk/users";
const unsubscribers = [
onMessage((m) => console.log(m.text)),
onJoin((u) => console.log("joined", u.profile.displayName)),
];
function teardown() {
for (const off of unsubscribers) off();
}
To group subscriptions and other resources for a single teardown, use
createPluginScope() from /lifecycle.
Request/response style calls (chat.send, input.raycast, the objects and
triggers operations) return a Promise instead, and reject on timeout or when
no host handler is wired. getPluginApiToken() rejects with typed errors (see
Auth). The runtime and environment APIs reject with SdkError
and accept scope, signal, and timeoutMs options (see
Runtime).
import { getId, getSessionId } from "@urth/metatell-sdk/user";
const userId = getId(); // persistent account id, or undefined without an account token
const sessionId = getSessionId(); // current room-session id, also available to guests
sessionId is the key used by presence (RemoteUser.sessionId), chat
(ChatMessage.from.sessionId, mentions), emotes, and object lipSync bindings.
See User Profile.
To authenticate calls to your own backend, exchange the session for a scoped
plugin API token with getPluginApiToken(). See Auth.