@laplace.live/persona-sdk 1.21.0 → 1.23.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.
@@ -17,7 +17,7 @@ export type ContentOrigin = 'bundled' | 'user';
17
17
  * ever an environment map, and a `.vmd` splits by content — `cameraMotion` for one that
18
18
  * frames a shot, `animation` for one that drives a rig.
19
19
  */
20
- export declare const ASSET_KINDS: readonly ["image", "video", "audio", "prop", "ibl", "lut", "animation", "cameraMotion"];
20
+ export declare const ASSET_KINDS: readonly ["image", "video", "audio", "prop", "ibl", "lut", "animation", "cameraMotion", "lyrics"];
21
21
  export type AssetKind = (typeof ASSET_KINDS)[number];
22
22
  /** Narrow a kind string to the set the asset registry owns — models and effects have their own. */
23
23
  export declare function isAssetKind(v: unknown): v is AssetKind;
@@ -48,6 +48,13 @@ export interface ContentRef {
48
48
  /** A model as the registry lists it. */
49
49
  export interface ModelRef extends ContentRef {
50
50
  kind: ModelFormat;
51
+ /** Entry file basename (`.model3.json`, `.vrm`), with no directory. Absent on older hosts. */
52
+ entryFile?: string;
53
+ /**
54
+ * `.vtube.json` basename, the name a VTS model-load hotkey stores (see `modelMatchesFile`); null
55
+ * without one. Only `model.list` fills it: absent on scene item refs, `model.register`'s answer, and older hosts.
56
+ */
57
+ vtubeFile?: string | null;
51
58
  }
52
59
  /** A registered object-source file. `exists` is false once the file is gone from disk. */
53
60
  export interface AssetRef extends ContentRef {
@@ -209,16 +216,60 @@ export interface SceneModelItem {
209
216
  export declare const OBJECT_SPACES: readonly ["2d", "3d"];
210
217
  export type ObjectSpace = (typeof OBJECT_SPACES)[number];
211
218
  export type CaptureKind = 'display' | 'window';
219
+ export declare const TEXT_ALIGNS: readonly ["left", "center", "right", "justify"];
220
+ export type TextAlign = (typeof TEXT_ALIGNS)[number];
221
+ /** `baseline` is the first line's baseline — Blender's Top Base-Line. */
222
+ export declare const TEXT_VERTICAL_ALIGNS: readonly ["top", "middle", "baseline", "bottom"];
223
+ export type TextVerticalAlign = (typeof TEXT_VERTICAL_ALIGNS)[number];
224
+ /** Blender's text-box overflow: spill past the box, shrink to fit it, or drop the lines that don't fit. */
225
+ export declare const TEXT_OVERFLOWS: readonly ["overflow", "scale", "truncate"];
226
+ export type TextOverflow = (typeof TEXT_OVERFLOWS)[number];
227
+ export declare const TEXT_STROKE_JOINS: readonly ["round", "miter", "bevel"];
228
+ export type TextStrokeJoin = (typeof TEXT_STROKE_JOINS)[number];
229
+ /**
230
+ * A system font face, named exactly: its PostScript name is the identity, since a family's
231
+ * nearest weight is not the face the user picked. The rest lets a machine without that face
232
+ * fall back to the closest one in the same family.
233
+ */
234
+ export interface TextFont {
235
+ postscriptName: string;
236
+ family: string;
237
+ weight: number;
238
+ italic: boolean;
239
+ /** CSS `font-stretch` percent; 100 is normal. */
240
+ stretch: number;
241
+ }
242
+ /**
243
+ * Keys one color out of an image, video or webpage, as OBS's Chroma Key filter does. Distance is
244
+ * BT.709 chroma at studio swing, so brightness never counts, and the three tolerances are OBS's
245
+ * slider values ÷ 1000.
246
+ */
247
+ export interface ChromaKey {
248
+ enabled: boolean;
249
+ /** Hex color made transparent. */
250
+ color: string;
251
+ /** Chroma distance from `color` that turns fully transparent. */
252
+ similarity: number;
253
+ /** Distance past `similarity` over which the edge fades back to opaque. */
254
+ smoothness: number;
255
+ /** Distance past `similarity` over which the key's tint desaturates out of the edge. */
256
+ spill: number;
257
+ }
212
258
  /** What an object renders. Mirrors VTube Studio's items and Warudo's screen/prop assets. */
213
259
  export type ObjectContent = {
214
260
  kind: 'image';
215
261
  assetId: string;
262
+ /** Absent keys nothing, as on older hosts. */
263
+ chromaKey?: ChromaKey;
216
264
  } | {
217
265
  kind: 'video';
218
266
  assetId: string;
219
267
  loop: boolean;
220
268
  muted: boolean;
221
269
  volume: number;
270
+ /** Held rather than played while shown, through a restart too; the playback position is not saved. */
271
+ paused: boolean;
272
+ chromaKey?: ChromaKey;
222
273
  } | {
223
274
  kind: 'prop';
224
275
  assetId: string;
@@ -237,16 +288,105 @@ export type ObjectContent = {
237
288
  css: string;
238
289
  /** Close the page while the object is hidden and reload it on show, as an OBS browser source can. */
239
290
  shutdownWhenHidden: boolean;
291
+ chromaKey?: ChromaKey;
240
292
  } | {
241
293
  kind: 'capture';
242
294
  source: CaptureKind;
243
295
  sourceId: string;
244
296
  label: string;
297
+ } | {
298
+ kind: 'text';
299
+ text: string;
300
+ /** null draws in the platform's default sans-serif. */
301
+ font: TextFont | null;
302
+ /** Em size, px; 3D reads px at the image quads' 1000 px per metre. */
303
+ size: number;
304
+ color: string;
305
+ /** Blender's shear: the slant as a fraction of height, -1..1. */
306
+ shear: number;
307
+ /** Em fractions added between characters and to each space. */
308
+ letterSpacing: number;
309
+ wordSpacing: number;
310
+ /** Line box as a multiple of `size`. */
311
+ lineHeight: number;
312
+ align: TextAlign;
313
+ verticalAlign: TextVerticalAlign;
314
+ /** Text box, px; 0 sizes that side to the text, and a set width wraps. */
315
+ boxWidth: number;
316
+ boxHeight: number;
317
+ overflow: TextOverflow;
318
+ /** Outside the glyphs, px; width 0 draws none. */
319
+ stroke: {
320
+ width: number;
321
+ color: string;
322
+ join: TextStrokeJoin;
323
+ };
324
+ /** px; opacity 0 draws none. */
325
+ shadow: {
326
+ color: string;
327
+ opacity: number;
328
+ offsetX: number;
329
+ offsetY: number;
330
+ blur: number;
331
+ };
332
+ /** A backing box around the text, px; opacity 0 draws none. */
333
+ plate: {
334
+ color: string;
335
+ opacity: number;
336
+ padding: number;
337
+ radius: number;
338
+ };
339
+ /** Karaoke: a lyrics clip paints what is sung in `color`, outlined in `strokeColor` (2D only). */
340
+ sung: {
341
+ color: string;
342
+ strokeColor: string;
343
+ };
344
+ /** 3D: extrusion depth and bevel as fractions of `size`; bevel segments. */
345
+ extrude: number;
346
+ bevel: number;
347
+ bevelResolution: number;
348
+ /** 3D surface: PBR roughness and metalness 0..1, and how strongly the text glows in its own colour. */
349
+ roughness: number;
350
+ metalness: number;
351
+ emission: number;
352
+ /** 3D: turn the text to face the camera every frame, ignoring the placement's rotation. */
353
+ faceCamera: boolean;
245
354
  };
355
+ /** The variants of {@link ObjectContent} a chroma key applies to: the flat media quads. */
356
+ export type KeyableContent = Extract<ObjectContent, {
357
+ kind: 'image' | 'video' | 'web';
358
+ }>;
359
+ /** The video variant of {@link ObjectContent}. */
360
+ export type VideoContent = Extract<ObjectContent, {
361
+ kind: 'video';
362
+ }>;
246
363
  /** The webpage variant of {@link ObjectContent}. */
247
364
  export type WebContent = Extract<ObjectContent, {
248
365
  kind: 'web';
249
366
  }>;
367
+ /** The text variant of {@link ObjectContent}. */
368
+ export type TextContent = Extract<ObjectContent, {
369
+ kind: 'text';
370
+ }>;
371
+ /** One face of a {@link FontFamilyInfo}. */
372
+ export interface FontFaceInfo {
373
+ postscriptName: string;
374
+ /** The subfamily as the font names it: `Semibold`, `W6`, `Bold Italic`. */
375
+ style: string;
376
+ weight: number;
377
+ italic: boolean;
378
+ /** CSS `font-stretch` percent. */
379
+ stretch: number;
380
+ /** A variable font's named instance. */
381
+ variable: boolean;
382
+ }
383
+ /** An installed font family and its faces. File paths never cross the wire. */
384
+ export interface FontFamilyInfo {
385
+ family: string;
386
+ /** Every name the family goes by, localized ones included, canonical first. */
387
+ names: string[];
388
+ faces: FontFaceInfo[];
389
+ }
250
390
  /** Where on a parent model an object rides. `root` is the model's own transform. */
251
391
  export type AttachAnchor = {
252
392
  kind: 'root';
@@ -365,6 +505,108 @@ export interface OrbitTransform {
365
505
  targetY: number;
366
506
  targetZ: number;
367
507
  }
508
+ /**
509
+ * How a following camera turns with its anchor — Warudo's Transposer binding modes. `world` follows
510
+ * position only; `yaw`, `yaw-pitch` and `full` also turn with it (Lock To Target With World Up, No Roll,
511
+ * and Lock To Target); `lazy` trails it, turning only as it passes (Simple Follow With World Up).
512
+ */
513
+ export declare const CAMERA_FOLLOW_BINDINGS: readonly ["world", "yaw", "yaw-pitch", "full", "lazy"];
514
+ export type CameraFollowBinding = (typeof CAMERA_FOLLOW_BINDINGS)[number];
515
+ /** Seconds a following camera takes to settle, 0 locking it: position along the view's own axes, then each turn. */
516
+ export interface CameraFollowDamping {
517
+ x: number;
518
+ y: number;
519
+ z: number;
520
+ yaw: number;
521
+ pitch: number;
522
+ roll: number;
523
+ }
524
+ /** The point a camera follows or aims at on a model: a humanoid bone, or its root. An object is tracked by its own origin. */
525
+ export type CameraAnchor = Extract<AttachAnchor, {
526
+ kind: 'root' | 'bone';
527
+ }>;
528
+ /**
529
+ * The layer a scene camera follows, aims at or focuses on: a VRM model or 3D object by id, or whichever model
530
+ * is primary as the scene changes. An id naming anything else heals to no tracking; a primary model that
531
+ * cannot be tracked holds the view.
532
+ */
533
+ export type CameraTrackTarget = {
534
+ target: 'primary';
535
+ instanceId?: never;
536
+ } | {
537
+ target?: never;
538
+ instanceId: string;
539
+ };
540
+ /** How a following camera tracks its layer, whichever layer that is. */
541
+ export interface SceneCameraFollowSettings {
542
+ /** Always the root on an object. */
543
+ anchor: CameraAnchor;
544
+ binding: CameraFollowBinding;
545
+ damping: CameraFollowDamping;
546
+ }
547
+ /**
548
+ * A scene camera following a layer. While set, `orbit` frames the layer as if its anchor rested at the stage
549
+ * origin, and the view moves with the anchor — placement, motion and tracking alike — without writing
550
+ * `orbit` back.
551
+ */
552
+ export type SceneCameraFollow = CameraTrackTarget & SceneCameraFollowSettings;
553
+ /**
554
+ * A scene camera turning to keep a layer at a spot on screen — Warudo's Composer. Screen values are
555
+ * fractions of the view: x from the left, y from the top.
556
+ */
557
+ export interface SceneCameraAimSettings {
558
+ /** Always the root on an object. */
559
+ anchor: CameraAnchor;
560
+ /** Where the anchor sits on screen, 0–1; 0.5 centres it. */
561
+ screenX: number;
562
+ screenY: number;
563
+ /** The camera holds still while the anchor stays inside this zone around its spot. */
564
+ deadZone: {
565
+ width: number;
566
+ height: number;
567
+ };
568
+ /** Past the dead zone the camera turns gradually; past this zone, at once. Never narrower than the dead zone. */
569
+ softZone: {
570
+ width: number;
571
+ height: number;
572
+ };
573
+ /** Shifts the soft zone off the spot, −0.5–0.5 of the slack between the zones. */
574
+ bias: {
575
+ x: number;
576
+ y: number;
577
+ };
578
+ /** Seconds to turn the anchor back into the dead zone, 0 turning at once. */
579
+ damping: {
580
+ horizontal: number;
581
+ vertical: number;
582
+ };
583
+ /**
584
+ * Aims `time` seconds (0–1, 0 off) ahead of a moving anchor, its velocity smoothed over `smoothing` (0–30);
585
+ * `ignoreY` leaves vertical motion out.
586
+ */
587
+ lookahead: {
588
+ time: number;
589
+ smoothing: number;
590
+ ignoreY: boolean;
591
+ };
592
+ }
593
+ export type SceneCameraAim = CameraTrackTarget & SceneCameraAimSettings;
594
+ /** A scene camera keeping a layer sharp under Depth of Field — Warudo's Focus Character. */
595
+ export interface SceneCameraFocusSettings {
596
+ /** Always the root on an object. */
597
+ anchor: CameraAnchor;
598
+ /** Seconds for the focus plane to catch up with the anchor, 0 at once. */
599
+ damping: number;
600
+ }
601
+ export type SceneCameraFocus = CameraTrackTarget & SceneCameraFocusSettings;
602
+ /** Noise-driven sway over the scene camera's own framing — Warudo's Handheld Movement. */
603
+ export interface SceneCameraHandheld {
604
+ enabled: boolean;
605
+ /** 0–1; the default 0.5 is a mild handheld. */
606
+ intensity: number;
607
+ /** 0–2; 1 sways at the authored pace. */
608
+ speed: number;
609
+ }
368
610
  /** Scene-level VRM camera. `orbit: null` = never framed — the first VRM load frames it from model height. */
369
611
  export interface SceneCamera {
370
612
  orbit: OrbitTransform | null;
@@ -379,6 +621,14 @@ export interface SceneCamera {
379
621
  * is set it overrides the framing every frame without writing it back.
380
622
  */
381
623
  clipAssetId: string | null;
624
+ /** The layer the view follows, or null. A camera motion overrides it. Absent on older hosts; gate on `camera-follow`. */
625
+ follow?: SceneCameraFollow | null;
626
+ /** The layer the view turns to keep on screen, or null. A camera motion overrides it. Absent on older hosts; gate on `camera-aim`. */
627
+ aim?: SceneCameraAim | null;
628
+ /** The layer Depth of Field keeps sharp, or null for the look-at point. Absent on older hosts; gate on `camera-focus`. */
629
+ focus?: SceneCameraFocus | null;
630
+ /** Handheld sway; a camera motion overrides it. Absent on older hosts; gate on `camera-handheld`. */
631
+ handheld?: SceneCameraHandheld;
382
632
  }
383
633
  /**
384
634
  * The slice of {@link SceneCamera} a saved pose snapshots and applies — a framing, never
@@ -490,8 +740,9 @@ export type SceneToneMapping = 'none' | 'neutral' | 'aces' | 'agx';
490
740
  export interface SceneBloom {
491
741
  enabled: boolean;
492
742
  mode: 'normal' | 'streak' | 'star';
493
- /** UI offset: the glow's brightness multiplier is 1 + intensity. */
743
+ /** The glow's brightness multiplier, as Warudo's; 0 adds no glow. */
494
744
  intensity: number;
745
+ /** Gamma-space brightness a channel must pass; squared into linear light, as Warudo's. */
495
746
  threshold: number;
496
747
  thresholdSmooth: number;
497
748
  radius: number;
@@ -760,7 +1011,7 @@ export interface SceneDroplets {
760
1011
  /** Specular glint on drops where the frame is transparent, so rain reads over the desktop (0 to 1). */
761
1012
  glints: number;
762
1013
  }
763
- /** Blend modes shared by Shoost's rim light and gradient. */
1014
+ /** Shoost's blend modes, as Gradient offers them. */
764
1015
  export type EffectBlendMode = (typeof EFFECT_BLEND_MODES)[number];
765
1016
  /** Solid, linear, or radial color overlay in scene or source coordinates. */
766
1017
  export interface EffectGradient {
@@ -804,11 +1055,10 @@ export interface SceneFlare {
804
1055
  raysIntensity: number;
805
1056
  raysOpacity: number;
806
1057
  }
807
- /** Directional silhouette lighting, optionally sharpened or applied to both sides. */
1058
+ /** Directional silhouette light, added like VTube Studio's backlight; optionally sharpened or two-sided. */
808
1059
  export interface SceneRim {
809
1060
  enabled: boolean;
810
1061
  mode: 'single' | 'double' | 'sharpenSingle' | 'sharpenDouble';
811
- blendMode: EffectBlendMode;
812
1062
  /** Rim tint (hex). */
813
1063
  color: string;
814
1064
  /** Normalized rim width, 0..1. */
@@ -1061,7 +1311,7 @@ export interface ScenePatch {
1061
1311
  * App-level features a client gates on (never version-sniff): `hello` and
1062
1312
  * `app.info` report them — the per-app mirror of {@link InstanceRuntime.capabilities}.
1063
1313
  */
1064
- 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", "tracking-lost", "motion-stop", "stage-capture", "model-movement", "object-pin-depth"];
1314
+ 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", "tracking-lost", "motion-stop", "stage-capture", "model-movement", "object-pin-depth", "text-objects", "camera-follow", "camera-aim", "camera-focus", "camera-handheld", "video-sound", "object-chroma-key"];
1065
1315
  export type AppCapability = (typeof APP_CAPABILITIES)[number];
1066
1316
  export declare function isAppCapability(v: unknown): v is AppCapability;
1067
1317
  /** What a loaded model instance can do; absent capabilities answer `unsupported-for-format`. */
@@ -1130,7 +1380,7 @@ export interface Hotkey {
1130
1380
  name: string;
1131
1381
  /** The VTS `Action` string verbatim; `action` is null when Persona cannot run it. */
1132
1382
  vtsAction: string;
1133
- action: 'toggle-expression' | 'play-motion' | 'remove-all-expressions' | 'load-model' | null;
1383
+ action: 'expression-toggle' | 'motion-play' | 'expression-clear' | 'model-load' | null;
1134
1384
  file: string;
1135
1385
  accelerator: string | null;
1136
1386
  global: boolean;
@@ -1153,11 +1403,22 @@ export interface HotkeyState extends HotkeyConfig {
1153
1403
  registered: string[];
1154
1404
  }
1155
1405
  /** Action kinds an app automation can carry today; servers may send kinds newer than this list. */
1156
- export declare const AUTOMATION_ACTION_KINDS: readonly ["effect-toggle", "effect-params", "effect-clip", "camera-pose", "reset-camera", "play-camera-motion", "stop-camera-motion", "layer-visibility", "stream-mode", "switch-scene", "toggle-expression", "play-motion", "play-audio", "audio-control", "remove-all-expressions", "load-model", "model-position"];
1406
+ export declare const AUTOMATION_ACTION_KINDS: readonly ["effect-toggle", "effect-params", "effect-clip", "camera-pose", "camera-reset", "camera-motion-play", "camera-motion-stop", "camera-follow", "camera-aim", "camera-focus", "camera-handheld", "layer-visibility", "text-set", "lyrics-play", "stream-mode", "scene-switch", "expression-toggle", "motion-play", "audio-play", "audio-control", "expression-clear", "model-load", "model-position"];
1157
1407
  export type AutomationActionKind = (typeof AUTOMATION_ACTION_KINDS)[number];
1408
+ /**
1409
+ * Deprecated action kind names, each mapped to its category-first replacement. Older hosts send them in
1410
+ * `actionKinds` and `Hotkey.action`, and older files store them; the client renames them on receipt.
1411
+ */
1412
+ export declare const LEGACY_AUTOMATION_ACTION_KINDS: ReadonlyMap<string, AutomationActionKind>;
1413
+ /** The current name of an action kind; kinds that were never renamed, known or not, pass through. */
1414
+ export declare function canonicalActionKind(kind: string): string;
1158
1415
  /** Setup kinds that finish loading before the sequence clock starts. */
1159
- export declare const AUTOMATION_BOUNDARY_KINDS: readonly ["switch-scene", "load-model"];
1160
- export type AutomationBoundaryKind = (typeof AUTOMATION_BOUNDARY_KINDS)[number];
1416
+ export declare const AUTOMATION_SETUP_KINDS: readonly ["scene-switch", "model-load"];
1417
+ export type AutomationSetupKind = (typeof AUTOMATION_SETUP_KINDS)[number];
1418
+ /** @deprecated Use `AUTOMATION_SETUP_KINDS`. */
1419
+ export declare const AUTOMATION_BOUNDARY_KINDS: readonly ["scene-switch", "model-load"];
1420
+ /** @deprecated Use `AutomationSetupKind`. */
1421
+ export type AutomationBoundaryKind = AutomationSetupKind;
1161
1422
  /**
1162
1423
  * One app automation as clients see it. Action kinds and scene targets drive derived
1163
1424
  * labels; other action payloads stay app-side.
@@ -13,13 +13,35 @@ import { TIME_INPUT_NAMES, TIME_INPUT_RANGES } from "../values/time.js";
13
13
  * ever an environment map, and a `.vmd` splits by content — `cameraMotion` for one that
14
14
  * frames a shot, `animation` for one that drives a rig.
15
15
  */
16
- export const ASSET_KINDS = ['image', 'video', 'audio', 'prop', 'ibl', 'lut', 'animation', 'cameraMotion'];
16
+ export const ASSET_KINDS = [
17
+ 'image',
18
+ 'video',
19
+ 'audio',
20
+ 'prop',
21
+ 'ibl',
22
+ 'lut',
23
+ 'animation',
24
+ 'cameraMotion',
25
+ 'lyrics',
26
+ ];
17
27
  /** Narrow a kind string to the set the asset registry owns — models and effects have their own. */
18
28
  export function isAssetKind(v) {
19
29
  return isOneOf(v, ASSET_KINDS);
20
30
  }
21
31
  // ---- Objects -------------------------------------------------------------------
22
32
  export const OBJECT_SPACES = ['2d', '3d'];
33
+ export const TEXT_ALIGNS = ['left', 'center', 'right', 'justify'];
34
+ /** `baseline` is the first line's baseline — Blender's Top Base-Line. */
35
+ export const TEXT_VERTICAL_ALIGNS = ['top', 'middle', 'baseline', 'bottom'];
36
+ /** Blender's text-box overflow: spill past the box, shrink to fit it, or drop the lines that don't fit. */
37
+ export const TEXT_OVERFLOWS = ['overflow', 'scale', 'truncate'];
38
+ export const TEXT_STROKE_JOINS = ['round', 'miter', 'bevel'];
39
+ /**
40
+ * How a following camera turns with its anchor — Warudo's Transposer binding modes. `world` follows
41
+ * position only; `yaw`, `yaw-pitch` and `full` also turn with it (Lock To Target With World Up, No Roll,
42
+ * and Lock To Target); `lazy` trails it, turning only as it passes (Simple Follow With World Up).
43
+ */
44
+ export const CAMERA_FOLLOW_BINDINGS = ['world', 'yaw', 'yaw-pitch', 'full', 'lazy'];
23
45
  export const SCENE_LIGHT_TYPES = ['directional', 'point', 'ambient', 'area', 'spot'];
24
46
  /**
25
47
  * Per-light shadow tier. `off` is the old `castShadow: false`; the rest raise
@@ -61,6 +83,20 @@ export const APP_CAPABILITIES = [
61
83
  * one pinned to a Live2D model takes `attach.depth` in that model's stack, as a Live2D item does.
62
84
  */
63
85
  'object-pin-depth',
86
+ /** `text` object content and `fonts.list`. */
87
+ 'text-objects',
88
+ /** `SceneCamera.follow`. */
89
+ 'camera-follow',
90
+ /** `SceneCamera.aim`. */
91
+ 'camera-aim',
92
+ /** `SceneCamera.focus`. */
93
+ 'camera-focus',
94
+ /** `SceneCamera.handheld`. */
95
+ 'camera-handheld',
96
+ /** `object.setContent` edits a video's `loop`, `muted` and `volume` in place; its sound follows the output device. */
97
+ 'video-sound',
98
+ /** Image, video and webpage content takes `chromaKey`, which `object.setContent` edits in place. */
99
+ 'object-chroma-key',
64
100
  ];
65
101
  export function isAppCapability(v) {
66
102
  return isOneOf(v, APP_CAPABILITIES);
@@ -72,25 +108,51 @@ export const AUTOMATION_ACTION_KINDS = [
72
108
  'effect-params',
73
109
  'effect-clip',
74
110
  'camera-pose',
75
- 'reset-camera',
76
- 'play-camera-motion',
77
- 'stop-camera-motion',
111
+ 'camera-reset',
112
+ 'camera-motion-play',
113
+ 'camera-motion-stop',
114
+ 'camera-follow',
115
+ 'camera-aim',
116
+ 'camera-focus',
117
+ 'camera-handheld',
78
118
  'layer-visibility',
119
+ 'text-set',
120
+ 'lyrics-play',
79
121
  'stream-mode',
80
- 'switch-scene',
81
- 'toggle-expression',
82
- 'play-motion',
83
- 'play-audio',
122
+ 'scene-switch',
123
+ 'expression-toggle',
124
+ 'motion-play',
125
+ 'audio-play',
84
126
  'audio-control',
85
- 'remove-all-expressions',
86
- 'load-model',
127
+ 'expression-clear',
128
+ 'model-load',
87
129
  'model-position',
88
130
  ];
131
+ /**
132
+ * Deprecated action kind names, each mapped to its category-first replacement. Older hosts send them in
133
+ * `actionKinds` and `Hotkey.action`, and older files store them; the client renames them on receipt.
134
+ */
135
+ export const LEGACY_AUTOMATION_ACTION_KINDS = new Map([
136
+ ['reset-camera', 'camera-reset'],
137
+ ['play-camera-motion', 'camera-motion-play'],
138
+ ['stop-camera-motion', 'camera-motion-stop'],
139
+ ['set-text', 'text-set'],
140
+ ['lyrics', 'lyrics-play'],
141
+ ['switch-scene', 'scene-switch'],
142
+ ['toggle-expression', 'expression-toggle'],
143
+ ['play-motion', 'motion-play'],
144
+ ['play-audio', 'audio-play'],
145
+ ['remove-all-expressions', 'expression-clear'],
146
+ ['load-model', 'model-load'],
147
+ ]);
148
+ /** The current name of an action kind; kinds that were never renamed, known or not, pass through. */
149
+ export function canonicalActionKind(kind) {
150
+ return LEGACY_AUTOMATION_ACTION_KINDS.get(kind) ?? kind;
151
+ }
89
152
  /** Setup kinds that finish loading before the sequence clock starts. */
90
- export const AUTOMATION_BOUNDARY_KINDS = [
91
- 'switch-scene',
92
- 'load-model',
93
- ];
153
+ export const AUTOMATION_SETUP_KINDS = ['scene-switch', 'model-load'];
154
+ /** @deprecated Use `AUTOMATION_SETUP_KINDS`. */
155
+ export const AUTOMATION_BOUNDARY_KINDS = AUTOMATION_SETUP_KINDS;
94
156
  // ---- Settings ------------------------------------------------------------------
95
157
  export const TRACKING_SOURCE_IDS = ['persona-ios', 'ifacialmocap', 'vts-ios'];
96
158
  /** Body-pose protocols. Every one so far is UDP with a configurable port. */
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@laplace.live/persona-sdk",
3
- "version": "1.21.0",
3
+ "version": "1.23.0",
4
4
  "description": "TypeScript SDK and wire schema for the LAPLACE Persona plugin API",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
- "author": "LAPLACE <s@laplace.live>",
7
+ "author": "LAPLACE Live! <s@laplace.live>",
8
8
  "repository": {
9
9
  "type": "git",
10
10
  "url": "https://github.com/laplace-live/persona",
@@ -28,7 +28,7 @@
28
28
  "devDependencies": {
29
29
  "rimraf": "^6.1.3",
30
30
  "typescript": "~6.0.3",
31
- "vitest": "^5.0.1"
31
+ "vitest": "^5.0.2"
32
32
  },
33
33
  "engines": {
34
34
  "node": ">=24"