@laplace.live/persona-sdk 1.11.1 → 1.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -11,6 +11,7 @@ export * from './values/gltf-extensions.ts';
11
11
  export * from './values/guards.ts';
12
12
  export * from './values/hands.ts';
13
13
  export * from './values/hotkeys.ts';
14
+ export * from './values/item-transition.ts';
14
15
  export * from './values/labels.ts';
15
16
  export * from './values/limits.ts';
16
17
  export * from './values/lipsync.ts';
package/dist/index.js CHANGED
@@ -13,6 +13,7 @@ export * from "./values/gltf-extensions.js";
13
13
  export * from "./values/guards.js";
14
14
  export * from "./values/hands.js";
15
15
  export * from "./values/hotkeys.js";
16
+ export * from "./values/item-transition.js";
16
17
  export * from "./values/labels.js";
17
18
  export * from "./values/limits.js";
18
19
  export * from "./values/lipsync.js";
@@ -0,0 +1,23 @@
1
+ export declare const ITEM_TRANSITION_STYLES: readonly ["glitch", "dither", "pop", "cut"];
2
+ export type ItemTransitionStyle = (typeof ITEM_TRANSITION_STYLES)[number];
3
+ /** One ramp length for a model switch, an object fade, or a body's entrance and exit. */
4
+ export declare const ITEM_TRANSITION_DEFAULT_MS = 300;
5
+ export declare const ITEM_TRANSITION_MAX_MS = 5000;
6
+ export interface ItemTransition {
7
+ /**
8
+ * `glitch` tears and burns through a dithered dissolve, `dither` is the plain screen-door,
9
+ * `pop` scales in and out, `cut` switches.
10
+ */
11
+ style: ItemTransitionStyle;
12
+ /** Length of the ramp either way, 0–`ITEM_TRANSITION_MAX_MS`; 0 behaves as `cut`. */
13
+ durationMs: number;
14
+ }
15
+ export declare function defaultItemTransition(): ItemTransition;
16
+ /** A per-call departure from the scene's item transition, for `stage.spawn`. */
17
+ export interface SpawnTransition {
18
+ style?: ItemTransitionStyle;
19
+ /** Entrance ramp, 0–`ITEM_TRANSITION_MAX_MS`; defaults to the scene's duration. */
20
+ inMs?: number;
21
+ /** Exit ramp — expiry, eviction and clears — 0–`ITEM_TRANSITION_MAX_MS`; defaults to the scene's duration. */
22
+ outMs?: number;
23
+ }
@@ -0,0 +1,9 @@
1
+ // How stage items appear and disappear — models, objects and spawned bodies alike. Per scene,
2
+ // on `SceneEnvironment.itemTransition`; `stage.spawn` may override it per call.
3
+ export const ITEM_TRANSITION_STYLES = ['glitch', 'dither', 'pop', 'cut'];
4
+ /** One ramp length for a model switch, an object fade, or a body's entrance and exit. */
5
+ export const ITEM_TRANSITION_DEFAULT_MS = 300;
6
+ export const ITEM_TRANSITION_MAX_MS = 5000;
7
+ export function defaultItemTransition() {
8
+ return { style: 'glitch', durationMs: ITEM_TRANSITION_DEFAULT_MS };
9
+ }
@@ -152,6 +152,14 @@ export declare const PLACE_2D_SCALE_MIN = 0.01;
152
152
  export declare const PLACE_2D_SCALE_MAX = 50;
153
153
  export declare const PLACE_3D_SCALE_MIN = 0.01;
154
154
  export declare const PLACE_3D_SCALE_MAX = 100;
155
+ /** Objects one `object.addMany` call may append. */
156
+ export declare const OBJECT_ADD_MANY_MAX = 100;
157
+ /** `stage.spawn` bounds: bodies per call, bodies alive at once (the oldest make room), scatter and throw ranges, lifetime. */
158
+ export declare const SPAWN_COUNT_MAX = 200;
159
+ export declare const SPAWN_ALIVE_MAX = 500;
160
+ export declare const SPAWN_SPREAD_MAX = 20;
161
+ export declare const SPAWN_SPEED_MAX = 50;
162
+ export declare const SPAWN_TTL_MAX_MS = 600000;
155
163
  /** Web object viewport bounds, CSS px per side. */
156
164
  export declare const WEB_SIZE_MIN = 16;
157
165
  export declare const WEB_SIZE_MAX = 7680;
@@ -272,6 +272,14 @@ export const PLACE_2D_SCALE_MIN = 0.01;
272
272
  export const PLACE_2D_SCALE_MAX = 50;
273
273
  export const PLACE_3D_SCALE_MIN = 0.01;
274
274
  export const PLACE_3D_SCALE_MAX = 100;
275
+ /** Objects one `object.addMany` call may append. */
276
+ export const OBJECT_ADD_MANY_MAX = 100;
277
+ /** `stage.spawn` bounds: bodies per call, bodies alive at once (the oldest make room), scatter and throw ranges, lifetime. */
278
+ export const SPAWN_COUNT_MAX = 200;
279
+ export const SPAWN_ALIVE_MAX = 500;
280
+ export const SPAWN_SPREAD_MAX = 20;
281
+ export const SPAWN_SPEED_MAX = 50;
282
+ export const SPAWN_TTL_MAX_MS = 600_000;
275
283
  /** Web object viewport bounds, CSS px per side. */
276
284
  export const WEB_SIZE_MIN = 16;
277
285
  export const WEB_SIZE_MAX = 7680;
@@ -1,5 +1,6 @@
1
1
  import type { Binding, BindingEditorData } from '../values/bindings.ts';
2
2
  import type { ControllerMovementConfig, ControllerState } from '../values/controller.ts';
3
+ import type { SpawnTransition } from '../values/item-transition.ts';
3
4
  import type { LipSyncCalibrationCommand, LipSyncConfig, LipSyncMode, LipSyncState } from '../values/lipsync.ts';
4
5
  import type { SceneInspection } from '../values/stage-info.ts';
5
6
  import type { EventName } from './events.ts';
@@ -168,10 +169,21 @@ export interface InstanceInfoResponse {
168
169
  export interface ObjectAddRequest {
169
170
  content: ObjectContent;
170
171
  name?: string;
172
+ /** Initial placement, so the object never draws a frame at the default one. Omitted axes keep it. */
173
+ place2d?: Partial<Place2D>;
174
+ place3d?: Partial<Place3D>;
171
175
  }
172
176
  export interface ObjectAddResponse {
173
177
  instanceId: string;
174
178
  }
179
+ /** Up to `OBJECT_ADD_MANY_MAX` objects as one scene edit: one stage apply, one persist, one undo step. */
180
+ export interface ObjectAddManyRequest {
181
+ objects: ObjectAddRequest[];
182
+ }
183
+ export interface ObjectAddManyResponse {
184
+ /** In request order. */
185
+ instanceIds: string[];
186
+ }
175
187
  export interface ObjectRenameRequest {
176
188
  instanceId: string;
177
189
  name: string;
@@ -414,6 +426,44 @@ export interface StageResetTransformRequest {
414
426
  export type StageResetTransformResponse = EmptyResponse;
415
427
  export type StageResetCameraRequest = EmptyRequest;
416
428
  export type StageResetCameraResponse = EmptyResponse;
429
+ /** A world-space vector: metres, or metres per second for a velocity. */
430
+ export interface StageVector {
431
+ x: number;
432
+ y: number;
433
+ z: number;
434
+ }
435
+ /**
436
+ * Drop physics-driven copies of a prop asset onto the stage. They live in the renderer only —
437
+ * no scene item, no undo, no persistence — and clear with the scene, with Physics, or on
438
+ * `stage.clearSpawned`. Needs the scene's Physics switch on (`invalid-state` otherwise).
439
+ */
440
+ export interface StageSpawnRequest {
441
+ /** A registered `prop` asset. */
442
+ assetId: string;
443
+ /** 1–`SPAWN_COUNT_MAX`; default 1. Past `SPAWN_ALIVE_MAX` alive bodies, the oldest make room. */
444
+ count?: number;
445
+ /** Centre of the scatter box, metres; default `{ x: 0, y: 3, z: 0 }`, above where an avatar stands. */
446
+ origin?: StageVector;
447
+ /** Edge of the scatter box around `origin`, 0–`SPAWN_SPREAD_MAX` metres; default 1. */
448
+ spread?: number;
449
+ /** Initial velocity every body shares, each axis within ±`SPAWN_SPEED_MAX`; default at rest. */
450
+ velocity?: StageVector;
451
+ /** Placement scale, `PLACE_3D_SCALE_MIN`–`PLACE_3D_SCALE_MAX`; default 1. */
452
+ scale?: number;
453
+ /** Lifetime before a body vanishes, 0–`SPAWN_TTL_MAX_MS`; 0 keeps it until cleared. Default 30000. */
454
+ ttlMs?: number;
455
+ /** How these bodies appear and disappear; omitted fields take the scene's `itemTransition`. */
456
+ transition?: SpawnTransition;
457
+ }
458
+ export interface StageSpawnResponse {
459
+ spawned: number;
460
+ /** Bodies alive after this call, across every asset. */
461
+ alive: number;
462
+ }
463
+ export type StageClearSpawnedRequest = EmptyRequest;
464
+ export interface StageClearSpawnedResponse {
465
+ cleared: number;
466
+ }
417
467
  export type AppInfoRequest = EmptyRequest;
418
468
  export interface AppInfoResponse {
419
469
  name: string;
@@ -759,6 +809,10 @@ export interface MethodMap {
759
809
  request: ObjectAddRequest;
760
810
  response: ObjectAddResponse;
761
811
  };
812
+ 'object.addMany': {
813
+ request: ObjectAddManyRequest;
814
+ response: ObjectAddManyResponse;
815
+ };
762
816
  'object.rename': {
763
817
  request: ObjectRenameRequest;
764
818
  response: ObjectRenameResponse;
@@ -926,6 +980,14 @@ export interface MethodMap {
926
980
  request: StageResetCameraRequest;
927
981
  response: StageResetCameraResponse;
928
982
  };
983
+ 'stage.spawn': {
984
+ request: StageSpawnRequest;
985
+ response: StageSpawnResponse;
986
+ };
987
+ 'stage.clearSpawned': {
988
+ request: StageClearSpawnedRequest;
989
+ response: StageClearSpawnedResponse;
990
+ };
929
991
  'app.info': {
930
992
  request: AppInfoRequest;
931
993
  response: AppInfoResponse;
@@ -1,6 +1,6 @@
1
1
  import * as z from 'zod';
2
2
  import type { MethodName } from '../methods.ts';
3
- import type { HotkeyConfig, ObjectContent } from '../types.ts';
3
+ import type { HotkeyConfig, ObjectContent, Place2D, Place3D } from '../types.ts';
4
4
  /** A complete transition replacement; scene.patch remains stage-owned for its other slices. */
5
5
  export declare const SceneTransitionSchema: z.ZodObject<{
6
6
  type: z.ZodEnum<{
@@ -132,6 +132,16 @@ export declare const requestSchemas: {
132
132
  'object.add': z.ZodObject<{
133
133
  content: z.ZodCustom<ObjectContent, ObjectContent>;
134
134
  name: z.ZodOptional<z.ZodString>;
135
+ place2d: z.ZodOptional<z.ZodCustom<Partial<Place2D>, Partial<Place2D>>>;
136
+ place3d: z.ZodOptional<z.ZodCustom<Partial<Place3D>, Partial<Place3D>>>;
137
+ }, z.core.$strip>;
138
+ 'object.addMany': z.ZodObject<{
139
+ objects: z.ZodArray<z.ZodObject<{
140
+ content: z.ZodCustom<ObjectContent, ObjectContent>;
141
+ name: z.ZodOptional<z.ZodString>;
142
+ place2d: z.ZodOptional<z.ZodCustom<Partial<Place2D>, Partial<Place2D>>>;
143
+ place3d: z.ZodOptional<z.ZodCustom<Partial<Place3D>, Partial<Place3D>>>;
144
+ }, z.core.$strip>>;
135
145
  }, z.core.$strip>;
136
146
  'object.setContent': z.ZodObject<{
137
147
  instanceId: z.ZodString;
@@ -297,6 +307,33 @@ export declare const requestSchemas: {
297
307
  'speech.stop': z.ZodObject<{
298
308
  instanceId: z.ZodOptional<z.ZodString>;
299
309
  }, z.core.$strip>;
310
+ 'stage.spawn': z.ZodObject<{
311
+ assetId: z.ZodString;
312
+ count: z.ZodOptional<z.ZodNumber>;
313
+ origin: z.ZodOptional<z.ZodObject<{
314
+ x: z.ZodNumber;
315
+ y: z.ZodNumber;
316
+ z: z.ZodNumber;
317
+ }, z.core.$strip>>;
318
+ spread: z.ZodOptional<z.ZodNumber>;
319
+ velocity: z.ZodOptional<z.ZodObject<{
320
+ x: z.ZodNumber;
321
+ y: z.ZodNumber;
322
+ z: z.ZodNumber;
323
+ }, z.core.$strip>>;
324
+ scale: z.ZodOptional<z.ZodNumber>;
325
+ ttlMs: z.ZodOptional<z.ZodNumber>;
326
+ transition: z.ZodOptional<z.ZodObject<{
327
+ style: z.ZodOptional<z.ZodEnum<{
328
+ glitch: "glitch";
329
+ dither: "dither";
330
+ pop: "pop";
331
+ cut: "cut";
332
+ }>>;
333
+ inMs: z.ZodOptional<z.ZodNumber>;
334
+ outMs: z.ZodOptional<z.ZodNumber>;
335
+ }, z.core.$strip>>;
336
+ }, z.core.$strip>;
300
337
  'events.subscribe': z.ZodObject<{
301
338
  events: z.ZodArray<z.ZodCustom<keyof import("../events.ts").EventMap, keyof import("../events.ts").EventMap>>;
302
339
  }, z.core.$strip>;
@@ -1,7 +1,8 @@
1
1
  import * as z from 'zod';
2
2
  import { CONTROLLER_DEAD_ZONE_MAX } from "../../values/controller.js";
3
3
  import { isRecord } from "../../values/guards.js";
4
- import { SCENE_COLOR_RE, SPEECH_URL_MAX_LENGTH, STORAGE_KEY_MAX_LENGTH, STORAGE_VALUE_MAX_LENGTH, } from "../../values/limits.js";
4
+ import { ITEM_TRANSITION_STYLES } from "../../values/item-transition.js";
5
+ import { OBJECT_ADD_MANY_MAX, SCENE_COLOR_RE, SPEECH_URL_MAX_LENGTH, STORAGE_KEY_MAX_LENGTH, STORAGE_VALUE_MAX_LENGTH, } from "../../values/limits.js";
5
6
  import { LIP_SYNC_CALIBRATION_ACTIONS, LIP_SYNC_MODES, LIP_SYNC_PHONEMES, } from "../../values/lipsync.js";
6
7
  import { SCENE_TRANSITION_DURATION_MAX_MS, SCENE_TRANSITION_DURATION_MIN_MS, SCENE_TRANSITION_FADE_DEFAULT_MS, SCENE_TRANSITION_SWITCH_POINT_MAX, SCENE_TRANSITION_SWITCH_POINT_MIN, SCENE_TRANSITION_TYPES, } from "../../values/scene-transition.js";
7
8
  import { ASSET_KINDS, INJECT_TARGET_TYPES, POSE_SOURCE_IDS, TRACKING_SOURCE_IDS, TRACKING_SOURCE_KINDS, } from "../types.js";
@@ -59,6 +60,14 @@ const speechUrl = z
59
60
  return false;
60
61
  }
61
62
  }, 'url must be http(s) or data:audio/*');
63
+ // Placements are healed stage-side like `object.setPlacement`'s; only the container is gated here.
64
+ const objectAdd = z.object({
65
+ content: z.custom(isRecord, 'content must be an object'),
66
+ name: nonEmpty.optional(),
67
+ place2d: z.custom(isRecord, 'place2d must be an object').optional(),
68
+ place3d: z.custom(isRecord, 'place3d must be an object').optional(),
69
+ });
70
+ const stageVector = z.object({ x: z.number(), y: z.number(), z: z.number() });
62
71
  export const requestSchemas = {
63
72
  'lipSync.state': z.object({}),
64
73
  'lipSync.configure': lipSyncPatch,
@@ -85,10 +94,8 @@ export const requestSchemas = {
85
94
  }),
86
95
  'instance.add': z.object({ modelId: nonEmpty }),
87
96
  'instance.setModel': z.object({ instanceId: nonEmpty, modelId: nonEmpty }),
88
- 'object.add': z.object({
89
- content: z.custom(isRecord, 'content must be an object'),
90
- name: nonEmpty.optional(),
91
- }),
97
+ 'object.add': objectAdd,
98
+ 'object.addMany': z.object({ objects: z.array(objectAdd).min(1).max(OBJECT_ADD_MANY_MAX) }),
92
99
  'object.setContent': z.object({
93
100
  instanceId: nonEmpty,
94
101
  content: z.custom(isRecord, 'content must be an object'),
@@ -144,6 +151,23 @@ export const requestSchemas = {
144
151
  volume: z.number().min(0).max(1).optional(),
145
152
  }),
146
153
  'speech.stop': z.object({ instanceId: nonEmpty.optional() }),
154
+ // Main needs the asset id to resolve; the stage clamps the rest, so the numbers are gated shallowly.
155
+ 'stage.spawn': z.object({
156
+ assetId: nonEmpty,
157
+ count: z.number().optional(),
158
+ origin: stageVector.optional(),
159
+ spread: z.number().optional(),
160
+ velocity: stageVector.optional(),
161
+ scale: z.number().optional(),
162
+ ttlMs: z.number().optional(),
163
+ transition: z
164
+ .object({
165
+ style: z.enum(ITEM_TRANSITION_STYLES).optional(),
166
+ inMs: z.number().optional(),
167
+ outMs: z.number().optional(),
168
+ })
169
+ .optional(),
170
+ }),
147
171
  'events.subscribe': z.object({ events: z.array(lenientEventNameSchema).min(1) }),
148
172
  'events.unsubscribe': z.object({ events: z.array(lenientEventNameSchema).optional() }),
149
173
  'param.inject': z.object({ entries: z.array(InjectEntrySchema).min(1) }),
@@ -1,5 +1,6 @@
1
1
  import type * as z from 'zod';
2
2
  import type { EFFECT_BLEND_MODES, EFFECT_SCOPES } from '../values/effect-schema.ts';
3
+ import type { ItemTransition } from '../values/item-transition.ts';
3
4
  import type { SCENE_TRANSITION_TYPES } from '../values/scene-transition.ts';
4
5
  import type { SettingsPatchSchema, SettingsSchema } from './schemas/settings.ts';
5
6
  import { type ArkitInputName } from '../values/arkit.ts';
@@ -922,6 +923,8 @@ export interface SceneEnvironment {
922
923
  * The simulated pose is never saved — switching it off restores each object's placement.
923
924
  */
924
925
  physics?: boolean;
926
+ /** How models, objects and spawned bodies appear and disappear; omitted by older hosts. */
927
+ itemTransition?: ItemTransition;
925
928
  effects: SceneEffects;
926
929
  /**
927
930
  * Built-in effects added as layers, in registry order — one keeps its row and tuning while
@@ -981,7 +984,7 @@ export interface ScenePatch {
981
984
  * App-level features a client gates on (never version-sniff): `hello` and
982
985
  * `app.info` report them — the per-app mirror of {@link InstanceRuntime.capabilities}.
983
986
  */
984
- export declare const APP_CAPABILITIES: readonly ["storage", "speech", "automations", "controllers", "model-editing", "asset-inspection", "layer-effects", "scene-transitions", "area-lights", "spot-lights", "camera-follow-lights", "shadow-filters", "environment-map-model"];
987
+ export declare const APP_CAPABILITIES: readonly ["storage", "speech", "automations", "controllers", "model-editing", "asset-inspection", "layer-effects", "scene-transitions", "area-lights", "spot-lights", "camera-follow-lights", "shadow-filters", "environment-map-model", "spawn"];
985
988
  export type AppCapability = (typeof APP_CAPABILITIES)[number];
986
989
  export declare function isAppCapability(v: unknown): v is AppCapability;
987
990
  /** What a loaded model instance can do; absent capabilities answer `unsupported-for-format`. */
@@ -45,6 +45,7 @@ export const APP_CAPABILITIES = [
45
45
  'camera-follow-lights',
46
46
  'shadow-filters',
47
47
  'environment-map-model',
48
+ 'spawn',
48
49
  ];
49
50
  export function isAppCapability(v) {
50
51
  return isOneOf(v, APP_CAPABILITIES);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@laplace.live/persona-sdk",
3
- "version": "1.11.1",
3
+ "version": "1.12.0",
4
4
  "description": "TypeScript SDK and wire schema for the LAPLACE Persona plugin API",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -28,13 +28,13 @@
28
28
  "devDependencies": {
29
29
  "rimraf": "^6.1.3",
30
30
  "typescript": "~6.0.3",
31
- "vitest": "^5.0.0"
31
+ "vitest": "^5.0.1"
32
32
  },
33
33
  "engines": {
34
34
  "node": ">=24"
35
35
  },
36
36
  "dependencies": {
37
- "zod": "^4.6.4"
37
+ "zod": "^4.6.5"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "rimraf dist && tsc -p tsconfig.build.json",