@laplace.live/persona-sdk
v1.24.0
Published
TypeScript SDK and wire schema for the LAPLACE Persona plugin API
Readme
@laplace.live/persona-sdk
TypeScript SDK and wire schema for the LAPLACE Persona plugin API — a token-authenticated WebSocket API for driving the avatar, scenes, expressions, motions, hotkeys, and tracking parameters from outside the app.
Isomorphic: runs in Node ≥24, Bun, browsers, and OBS browser sources on the global WebSocket.
One runtime dependency (zod, backing the wire schemas).
Setup
Enable the API in Persona under Advanced → Plugin API, create a key, and copy the token.
import { PersonaClient } from "@laplace.live/persona-sdk";
const persona = new PersonaClient({ token: "sk-lp-v1-…" });
await persona.connect();
// Typed request/response
const { scenes, activeSceneId } = await persona.call("scene.list");
await persona.call("expression.toggle", { name: "Smile" });
await persona.call("scene.patch", {
background: { mode: "color", color: "#112233", imageAssetId: null },
});
// Events (subscriptions survive reconnects)
persona.on("motion.started", (m) => console.log("playing", m.group));
// Parameter leases: the value keeps applying until released; the SDK owns the
// heartbeat, and if your process dies the parameter reverts within ~1 s.
const mouth = persona.driveParameter("MouthOpen", 0.8);
mouth.set(0.3);
mouth.release();By default the token travels as ?token= (works in browsers). From Node you can use an
Authorization: Bearer header instead by supplying a socket that can set headers, e.g. the
ws package (install it separately — it is not a
dependency of this SDK):
import WebSocket from "ws";
const persona = new PersonaClient({
token,
auth: "header",
createWebSocket: (url, headers) => new WebSocket(url, { headers }),
});Identifying your app
Pass clientInfo so your app shows up by name under Connected Clients in Persona's
settings (optional — unidentified clients work the same). The SDK re-declares it on every
reconnect; it is self-declared and display-only, never authorization:
const persona = new PersonaClient({
token,
clientInfo: { name: "My Overlay", version: "1.2.0", developer: "You" },
});Two server close codes are terminal and stop the reconnect loop: CLOSE_KEY_REVOKED (4001,
the key was revoked) and CLOSE_FORCE_DISCONNECTED (4002, the user disconnected the session
in Persona). The client reports them via onWarning and goes closed.
Treat the token like a password: it grants control of the app, including loading registered models and web overlays. The server listens on loopback unless LAN access is enabled in Persona's settings.
Registry and catalog metadata
model.list / asset.list return refs with provenance and attribution: assets carry
origin ('bundled' shipped with the app, 'user' registered by the user; models carry
the same as kind), and both may carry optional author / url credits sourced from the
app's content manifest.
CatalogItem is the transport-agnostic content-metadata shape behind pickers: a stable
id (scene refs key off it), an InventoryKind, display name, and optional
thumbnailUrl, version, author, url, and download (payload location + integrity
for items not yet on disk — Persona will use this to ship bundled content as
metadata-only rows downloaded from its CDN on demand).
