@laplace.live/persona-sdk 1.0.0 → 1.2.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.
@@ -0,0 +1,89 @@
1
+ /** VTube Studio hand inputs, extended with nizima LIVE's wrist Y rotation. */
2
+ export const HAND_INPUT_NAMES = [
3
+ 'HandLeftFound',
4
+ 'HandLeftPositionX',
5
+ 'HandLeftPositionY',
6
+ 'HandLeftPositionZ',
7
+ 'HandLeftAngleX',
8
+ 'HandLeftAngleY',
9
+ 'HandLeftAngleZ',
10
+ 'HandLeftOpen',
11
+ 'HandLeftFinger_1_Thumb',
12
+ 'HandLeftFinger_2_Index',
13
+ 'HandLeftFinger_3_Middle',
14
+ 'HandLeftFinger_4_Ring',
15
+ 'HandLeftFinger_5_Pinky',
16
+ 'HandRightFound',
17
+ 'HandRightPositionX',
18
+ 'HandRightPositionY',
19
+ 'HandRightPositionZ',
20
+ 'HandRightAngleX',
21
+ 'HandRightAngleY',
22
+ 'HandRightAngleZ',
23
+ 'HandRightOpen',
24
+ 'HandRightFinger_1_Thumb',
25
+ 'HandRightFinger_2_Index',
26
+ 'HandRightFinger_3_Middle',
27
+ 'HandRightFinger_4_Ring',
28
+ 'HandRightFinger_5_Pinky',
29
+ 'BothHandsFound',
30
+ 'HandDistance',
31
+ ];
32
+ const HAND_INPUT_SET = new Set(HAND_INPUT_NAMES);
33
+ /** Whether an input uses the canonical hand vocabulary. */
34
+ export function isHandInputName(input) {
35
+ return HAND_INPUT_SET.has(input);
36
+ }
37
+ /** Names nizima uses for VTS's numbered fingers and both-hands detection. */
38
+ export const NIZIMA_HAND_ALIASES = {
39
+ HandLeftFingerThumb: 'HandLeftFinger_1_Thumb',
40
+ HandLeftFingerIndex: 'HandLeftFinger_2_Index',
41
+ HandLeftFingerMiddle: 'HandLeftFinger_3_Middle',
42
+ HandLeftFingerRing: 'HandLeftFinger_4_Ring',
43
+ HandLeftFingerPinky: 'HandLeftFinger_5_Pinky',
44
+ HandRightFingerThumb: 'HandRightFinger_1_Thumb',
45
+ HandRightFingerIndex: 'HandRightFinger_2_Index',
46
+ HandRightFingerMiddle: 'HandRightFinger_3_Middle',
47
+ HandRightFingerRing: 'HandRightFinger_4_Ring',
48
+ HandRightFingerPinky: 'HandRightFinger_5_Pinky',
49
+ HandBothFound: 'BothHandsFound',
50
+ };
51
+ /** Canonicalize a hand name; aliases share canonical units on the plugin API. */
52
+ export function canonicalHandInputName(input) {
53
+ if (isHandInputName(input))
54
+ return input;
55
+ return Object.hasOwn(NIZIMA_HAND_ALIASES, input)
56
+ ? NIZIMA_HAND_ALIASES[input]
57
+ : null;
58
+ }
59
+ /** Angles are degrees; positions and distance use VTS's ten-unit scale. */
60
+ export const HAND_INPUT_RANGES = {
61
+ HandLeftFound: [0, 1],
62
+ HandLeftPositionX: [-10, 10],
63
+ HandLeftPositionY: [-10, 10],
64
+ HandLeftPositionZ: [-10, 10],
65
+ HandLeftAngleX: [-180, 180],
66
+ HandLeftAngleY: [-90, 90],
67
+ HandLeftAngleZ: [-180, 180],
68
+ HandLeftOpen: [0, 1],
69
+ HandLeftFinger_1_Thumb: [0, 1],
70
+ HandLeftFinger_2_Index: [0, 1],
71
+ HandLeftFinger_3_Middle: [0, 1],
72
+ HandLeftFinger_4_Ring: [0, 1],
73
+ HandLeftFinger_5_Pinky: [0, 1],
74
+ HandRightFound: [0, 1],
75
+ HandRightPositionX: [-10, 10],
76
+ HandRightPositionY: [-10, 10],
77
+ HandRightPositionZ: [-10, 10],
78
+ HandRightAngleX: [-180, 180],
79
+ HandRightAngleY: [-90, 90],
80
+ HandRightAngleZ: [-180, 180],
81
+ HandRightOpen: [0, 1],
82
+ HandRightFinger_1_Thumb: [0, 1],
83
+ HandRightFinger_2_Index: [0, 1],
84
+ HandRightFinger_3_Middle: [0, 1],
85
+ HandRightFinger_4_Ring: [0, 1],
86
+ HandRightFinger_5_Pinky: [0, 1],
87
+ BothHandsFound: [0, 1],
88
+ HandDistance: [0, 10],
89
+ };
@@ -0,0 +1,106 @@
1
+ export declare const LIP_SYNC_VOWELS: readonly ["A", "I", "U", "E", "O"];
2
+ export type LipSyncVowel = (typeof LIP_SYNC_VOWELS)[number];
3
+ export declare const LIP_SYNC_PHONEMES: readonly ["A", "I", "U", "E", "O", "S"];
4
+ export type LipSyncPhoneme = (typeof LIP_SYNC_PHONEMES)[number];
5
+ export declare const LIP_SYNC_MODES: readonly ["off", "always", "when-untracked"];
6
+ export type LipSyncMode = (typeof LIP_SYNC_MODES)[number];
7
+ /** Public limits, shared by the settings healer, the wire schema, and the panel sliders. */
8
+ export declare const LIP_SYNC_GAIN_MAX = 30;
9
+ export declare const LIP_SYNC_NOISE_GATE_MIN = -60;
10
+ export declare const LIP_SYNC_SMOOTHING_MAX = 0.3;
11
+ /** Local microphone calibration; each sample is a 12-coefficient MFCC vector. */
12
+ export interface LipSyncProfile {
13
+ deviceId: string;
14
+ deviceLabel: string;
15
+ updatedAt: number;
16
+ samples: Record<LipSyncPhoneme, number[][]>;
17
+ }
18
+ /** Calibration steps that carry no phoneme; `record` is the sixth action and takes one. */
19
+ export declare const LIP_SYNC_CALIBRATION_ACTIONS: readonly ["start", "cancel", "preview", "save", "reset"];
20
+ export type LipSyncCalibrationCommand = {
21
+ action: (typeof LIP_SYNC_CALIBRATION_ACTIONS)[number];
22
+ } | {
23
+ action: 'record';
24
+ phoneme: LipSyncPhoneme;
25
+ };
26
+ export interface LipSyncCalibrationState {
27
+ phase: 'ready' | 'recording' | 'verifying';
28
+ phoneme: LipSyncPhoneme | null;
29
+ progress: number;
30
+ completed: LipSyncPhoneme[];
31
+ error: 'too-quiet' | 'insufficient-data' | null;
32
+ }
33
+ /** One desktop microphone, shared by the scene's participating models. */
34
+ export interface LipSyncConfig {
35
+ enabled: boolean;
36
+ /** Empty selects the system's default input. */
37
+ deviceId: string;
38
+ /** Input gain in dB, 0..30. */
39
+ gain: number;
40
+ /** Silence threshold in dBFS, -60..0. */
41
+ noiseGate: number;
42
+ /** Volume and vowel smoothing in seconds, 0..0.3. */
43
+ smoothing: number;
44
+ }
45
+ export declare const DEFAULT_LIP_SYNC_CONFIG: Readonly<LipSyncConfig>;
46
+ /** Analyzer output before model-specific mapping. */
47
+ export interface LipSyncSample {
48
+ /** Mouth-open envelope, 0..1. */
49
+ volume: number;
50
+ /** Smoothed vowel weights sum to at most one; the remainder represents non-vowel audio. */
51
+ vowels: Record<LipSyncVowel, number>;
52
+ }
53
+ export interface LipSyncState {
54
+ config: LipSyncConfig;
55
+ status: 'off' | 'starting' | 'listening' | 'error';
56
+ error: 'permission' | 'device' | 'analysis' | null;
57
+ devices: {
58
+ deviceId: string;
59
+ label: string;
60
+ }[];
61
+ sample: LipSyncSample | null;
62
+ microphone: {
63
+ deviceId: string;
64
+ label: string;
65
+ } | null;
66
+ profile: Omit<LipSyncProfile, 'samples'> | null;
67
+ calibration: LipSyncCalibrationState | null;
68
+ }
69
+ /** Drop incomplete or malformed calibrations rather than feeding them to the analyzer. */
70
+ export declare function healLipSyncProfile(raw: unknown): LipSyncProfile | null;
71
+ /** Heal persisted configuration, retaining supported values within their public limits. */
72
+ export declare function healLipSyncConfig(raw: unknown): LipSyncConfig;
73
+ /** Whether a persisted per-model mode is supported. */
74
+ export declare function isLipSyncMode(value: unknown): value is LipSyncMode;
75
+ export declare const VOICE_INPUT_NAMES: readonly ["VoiceVolume", "VoiceFrequency", "VoiceVolumePlusMouthOpen", "VoiceFrequencyPlusMouthSmile", "VoiceA", "VoiceI", "VoiceU", "VoiceE", "VoiceO", "VoiceSilence", "VoiceMouthOpen", "VoiceMouthSpread"];
76
+ export type VoiceInputName = (typeof VOICE_INPUT_NAMES)[number];
77
+ export declare const VOICE_INPUT_RANGES: {
78
+ readonly VoiceVolume: readonly [0, 1];
79
+ readonly VoiceFrequency: readonly [0, 1];
80
+ readonly VoiceVolumePlusMouthOpen: readonly [0, 2];
81
+ readonly VoiceFrequencyPlusMouthSmile: readonly [0, 1];
82
+ readonly VoiceA: readonly [0, 1];
83
+ readonly VoiceI: readonly [0, 1];
84
+ readonly VoiceU: readonly [0, 1];
85
+ readonly VoiceE: readonly [0, 1];
86
+ readonly VoiceO: readonly [0, 1];
87
+ readonly VoiceSilence: readonly [0, 1];
88
+ readonly VoiceMouthOpen: readonly [0, 1];
89
+ readonly VoiceMouthSpread: readonly [-1, 1];
90
+ };
91
+ /** Semantic import aliases; source analyzer amplitudes need not match Persona's. */
92
+ export declare const NIZIMA_VOICE_ALIASES: {
93
+ readonly LipSyncVolume: "VoiceVolume";
94
+ readonly LipSyncMouthOpen: "VoiceMouthOpen";
95
+ readonly LipSyncMouthSpread: "VoiceMouthSpread";
96
+ readonly LipSyncMouthA: "VoiceA";
97
+ readonly LipSyncMouthI: "VoiceI";
98
+ readonly LipSyncMouthU: "VoiceU";
99
+ readonly LipSyncMouthE: "VoiceE";
100
+ readonly LipSyncMouthO: "VoiceO";
101
+ };
102
+ /**
103
+ * VTS-compatible binding inputs. Frequency projects vowel weights onto its conventional
104
+ * mouth-form axis; composite sums retain over-range values for the authored binding to clamp.
105
+ */
106
+ export declare function voiceInputs(sample: LipSyncSample, faceInputs?: Readonly<Partial<Record<'MouthOpen' | 'MouthSmile', number>>>): Record<VoiceInputName, number>;
@@ -0,0 +1,120 @@
1
+ import { finiteOr, isFiniteNumber, isRecord, nonEmptyString } from "./guards.js";
2
+ import { clamp } from "./limits.js";
3
+ export const LIP_SYNC_VOWELS = ['A', 'I', 'U', 'E', 'O'];
4
+ export const LIP_SYNC_PHONEMES = [...LIP_SYNC_VOWELS, 'S'];
5
+ export const LIP_SYNC_MODES = ['off', 'always', 'when-untracked'];
6
+ /** Public limits, shared by the settings healer, the wire schema, and the panel sliders. */
7
+ export const LIP_SYNC_GAIN_MAX = 30;
8
+ export const LIP_SYNC_NOISE_GATE_MIN = -60;
9
+ export const LIP_SYNC_SMOOTHING_MAX = 0.3;
10
+ /** Calibration steps that carry no phoneme; `record` is the sixth action and takes one. */
11
+ export const LIP_SYNC_CALIBRATION_ACTIONS = ['start', 'cancel', 'preview', 'save', 'reset'];
12
+ export const DEFAULT_LIP_SYNC_CONFIG = {
13
+ enabled: false,
14
+ deviceId: '',
15
+ gain: 0,
16
+ noiseGate: -45,
17
+ smoothing: 0.08,
18
+ };
19
+ /** Drop incomplete or malformed calibrations rather than feeding them to the analyzer. */
20
+ export function healLipSyncProfile(raw) {
21
+ if (!isRecord(raw))
22
+ return null;
23
+ const deviceId = nonEmptyString(raw.deviceId);
24
+ if (deviceId === null ||
25
+ typeof raw.deviceLabel !== 'string' ||
26
+ !isFiniteNumber(raw.updatedAt) ||
27
+ raw.updatedAt < 0 ||
28
+ !isRecord(raw.samples)) {
29
+ return null;
30
+ }
31
+ const samples = { A: [], I: [], U: [], E: [], O: [], S: [] };
32
+ for (const phoneme of LIP_SYNC_PHONEMES) {
33
+ const vectors = raw.samples[phoneme];
34
+ if (!Array.isArray(vectors) || vectors.length < 12 || vectors.length > 40)
35
+ return null;
36
+ for (const vector of vectors) {
37
+ if (!Array.isArray(vector) || vector.length !== 12 || !vector.every(isFiniteNumber))
38
+ return null;
39
+ samples[phoneme].push([...vector]);
40
+ }
41
+ }
42
+ return { deviceId, deviceLabel: raw.deviceLabel, updatedAt: raw.updatedAt, samples };
43
+ }
44
+ /** Heal persisted configuration, retaining supported values within their public limits. */
45
+ export function healLipSyncConfig(raw) {
46
+ const value = isRecord(raw) ? raw : {};
47
+ return {
48
+ enabled: typeof value.enabled === 'boolean' ? value.enabled : DEFAULT_LIP_SYNC_CONFIG.enabled,
49
+ deviceId: typeof value.deviceId === 'string' ? value.deviceId : DEFAULT_LIP_SYNC_CONFIG.deviceId,
50
+ gain: clamp(finiteOr(value.gain, DEFAULT_LIP_SYNC_CONFIG.gain), 0, LIP_SYNC_GAIN_MAX),
51
+ noiseGate: clamp(finiteOr(value.noiseGate, DEFAULT_LIP_SYNC_CONFIG.noiseGate), LIP_SYNC_NOISE_GATE_MIN, 0),
52
+ smoothing: clamp(finiteOr(value.smoothing, DEFAULT_LIP_SYNC_CONFIG.smoothing), 0, LIP_SYNC_SMOOTHING_MAX),
53
+ };
54
+ }
55
+ /** Whether a persisted per-model mode is supported. */
56
+ export function isLipSyncMode(value) {
57
+ return LIP_SYNC_MODES.some(mode => mode === value);
58
+ }
59
+ export const VOICE_INPUT_NAMES = [
60
+ 'VoiceVolume',
61
+ 'VoiceFrequency',
62
+ 'VoiceVolumePlusMouthOpen',
63
+ 'VoiceFrequencyPlusMouthSmile',
64
+ 'VoiceA',
65
+ 'VoiceI',
66
+ 'VoiceU',
67
+ 'VoiceE',
68
+ 'VoiceO',
69
+ 'VoiceSilence',
70
+ 'VoiceMouthOpen',
71
+ 'VoiceMouthSpread',
72
+ ];
73
+ export const VOICE_INPUT_RANGES = {
74
+ VoiceVolume: [0, 1],
75
+ VoiceFrequency: [0, 1],
76
+ VoiceVolumePlusMouthOpen: [0, 2],
77
+ VoiceFrequencyPlusMouthSmile: [0, 1],
78
+ VoiceA: [0, 1],
79
+ VoiceI: [0, 1],
80
+ VoiceU: [0, 1],
81
+ VoiceE: [0, 1],
82
+ VoiceO: [0, 1],
83
+ VoiceSilence: [0, 1],
84
+ VoiceMouthOpen: [0, 1],
85
+ VoiceMouthSpread: [-1, 1],
86
+ };
87
+ /** Semantic import aliases; source analyzer amplitudes need not match Persona's. */
88
+ export const NIZIMA_VOICE_ALIASES = {
89
+ LipSyncVolume: 'VoiceVolume',
90
+ LipSyncMouthOpen: 'VoiceMouthOpen',
91
+ LipSyncMouthSpread: 'VoiceMouthSpread',
92
+ LipSyncMouthA: 'VoiceA',
93
+ LipSyncMouthI: 'VoiceI',
94
+ LipSyncMouthU: 'VoiceU',
95
+ LipSyncMouthE: 'VoiceE',
96
+ LipSyncMouthO: 'VoiceO',
97
+ };
98
+ /**
99
+ * VTS-compatible binding inputs. Frequency projects vowel weights onto its conventional
100
+ * mouth-form axis; composite sums retain over-range values for the authored binding to clamp.
101
+ */
102
+ export function voiceInputs(sample, faceInputs) {
103
+ const { volume, vowels } = sample;
104
+ // Vowel projection, not measured pitch: https://github.com/DenchiSoft/VTubeStudio/wiki/Lipsync
105
+ const frequency = 0.5 + (volume * (-0.9 * vowels.A - 0.7 * vowels.I - 0.6 * vowels.U + vowels.E + 0.9 * vowels.O)) / 2;
106
+ return {
107
+ VoiceVolume: volume,
108
+ VoiceFrequency: frequency,
109
+ VoiceVolumePlusMouthOpen: volume + (faceInputs?.MouthOpen ?? 0),
110
+ VoiceFrequencyPlusMouthSmile: faceInputs?.MouthSmile === undefined ? frequency : faceInputs.MouthSmile + (frequency - 0.5) * 2,
111
+ VoiceA: volume * vowels.A,
112
+ VoiceI: volume * vowels.I,
113
+ VoiceU: volume * vowels.U,
114
+ VoiceE: volume * vowels.E,
115
+ VoiceO: volume * vowels.O,
116
+ VoiceSilence: 1 - volume,
117
+ VoiceMouthOpen: volume * (vowels.A + 0.4 * vowels.I + 0.4 * vowels.U + 0.7 * vowels.E + vowels.O),
118
+ VoiceMouthSpread: volume * (vowels.A + vowels.I - vowels.U + vowels.E - vowels.O),
119
+ };
120
+ }
@@ -14,7 +14,7 @@ export interface EventMap {
14
14
  'shortcut.state': {
15
15
  shortcuts: ShortcutInfo[];
16
16
  };
17
- /** `sources` maps source id status; optional so pre-multi-source servers still parse. */
17
+ /** Network channel aggregates; `sources` includes webcam status and is optional for older servers. */
18
18
  'tracking.status': {
19
19
  tracking: TrackingStatus;
20
20
  pose: PoseStatus;
@@ -1,8 +1,9 @@
1
1
  import type { Binding, BindingEditorData } from '../values/bindings.ts';
2
2
  import type { ControllerMovementConfig, ControllerState } from '../values/controller.ts';
3
+ import type { LipSyncCalibrationCommand, LipSyncConfig, LipSyncMode, LipSyncState } from '../values/lipsync.ts';
3
4
  import type { SceneInspection } from '../values/stage-info.ts';
4
5
  import type { EventName } from './events.ts';
5
- import type { AnchorOption, AppCapability, AssetKind, AssetRef, Attach, AttachHeadAngle, BindingInput, Expression, ExpressionPersistence, HotkeyConfig, HotkeyState, InjectEntry, InjectTarget, InstanceRuntime, JsonValue, ModelInfo, ModelRef, MotionGroup, MToonTuning, ObjectContent, ObjectLightOverride, ObjectSpace, Place2D, Place3D, PlayingMotion, PoseSourceId, PoseStatus, Scene, SceneItem, ScenePatch, SceneState, ScreenPlacement, Settings, SettingsPatch, ShortcutInfo, TrackingSourceConfig, TrackingSourceId, TrackingSourceKind, TrackingStatus, VrmPlacement } from './types.ts';
6
+ import type { AnchorOption, AppCapability, AssetKind, AssetRef, Attach, AttachHeadAngle, BindingInput, Expression, ExpressionPersistence, HandTrackingMode, HotkeyConfig, HotkeyState, InjectEntry, InjectTarget, InstanceRuntime, JsonValue, LayerEffectKey, LayerEffects, LayerEffectsPatch, MediaPipeConfig, ModelInfo, ModelRef, MotionGroup, MToonTuning, ObjectContent, ObjectLightOverride, ObjectSpace, Place2D, Place3D, PlayingMotion, PoseSourceId, PoseStatus, Scene, SceneItem, ScenePatch, SceneState, ScreenPlacement, Settings, SettingsPatch, ShortcutInfo, TrackingSourceConfig, TrackingSourceId, TrackingSourceKind, TrackingStatus, VrmPlacement } from './types.ts';
6
7
  /** Marker for methods that take no parameters; the client lets you omit the argument. */
7
8
  export type EmptyRequest = Record<never, never>;
8
9
  /** Marker for methods whose success response carries no data. */
@@ -76,11 +77,24 @@ export interface InstanceSetVisibleRequest {
76
77
  visible: boolean;
77
78
  }
78
79
  export type InstanceSetVisibleResponse = EmptyResponse;
80
+ /** Edits one model or object's source effects; gate on the `layer-effects` app capability. */
81
+ export interface InstanceSetEffectsRequest {
82
+ instanceId: string;
83
+ effects: LayerEffectsPatch;
84
+ /** Replaces the added-effect list; omitted preserves it. Enabled effects always appear. */
85
+ effectLayers?: LayerEffectKey[];
86
+ }
87
+ export interface InstanceSetEffectsResponse {
88
+ effects: LayerEffects;
89
+ effectLayers: LayerEffectKey[];
90
+ }
79
91
  /** Omitted fields keep their binding; null stops tracking that channel for this instance. */
80
92
  export interface InstanceSetTrackingSourcesRequest {
81
93
  instanceId: string;
82
94
  faceSourceId?: string | null;
83
95
  poseSourceId?: string | null;
96
+ handSourceId?: string | null;
97
+ handTrackingMode?: HandTrackingMode;
84
98
  }
85
99
  export type InstanceSetTrackingSourcesResponse = EmptyResponse;
86
100
  export interface InstanceSetControllerMovementRequest {
@@ -90,6 +104,21 @@ export interface InstanceSetControllerMovementRequest {
90
104
  export interface InstanceSetControllerMovementResponse {
91
105
  movement: ControllerMovementConfig;
92
106
  }
107
+ export interface InstanceSetLipSyncRequest {
108
+ instanceId?: string;
109
+ mode: LipSyncMode;
110
+ }
111
+ export interface InstanceSetLipSyncResponse {
112
+ mode: LipSyncMode;
113
+ }
114
+ export type LipSyncStateRequest = EmptyRequest;
115
+ export type LipSyncStateResponse = LipSyncState;
116
+ export type LipSyncConfigureRequest = Partial<LipSyncConfig>;
117
+ export type LipSyncConfigureResponse = LipSyncConfig;
118
+ export type LipSyncRestartRequest = EmptyRequest;
119
+ export type LipSyncRestartResponse = EmptyResponse;
120
+ export type LipSyncCalibrateRequest = LipSyncCalibrationCommand;
121
+ export type LipSyncCalibrateResponse = LipSyncState;
93
122
  export interface InstanceReorderRequest {
94
123
  /** Full z-order within the scene; ids not listed keep their relative order at the end. */
95
124
  orderedInstanceIds: string[];
@@ -311,6 +340,7 @@ export interface SettingsPatchResponse {
311
340
  settings: Settings;
312
341
  }
313
342
  export interface TrackingSetEnabledRequest {
343
+ /** Enables network face sources; webcam tracking is controlled by its source's enabled flag. */
314
344
  enabled: boolean;
315
345
  }
316
346
  export type TrackingSetEnabledResponse = EmptyResponse;
@@ -319,6 +349,7 @@ export interface TrackingSetSourceRequest {
319
349
  }
320
350
  export type TrackingSetSourceResponse = EmptyResponse;
321
351
  export interface PoseSetEnabledRequest {
352
+ /** Enables network body sources; webcam tracking is controlled by its source's enabled flag. */
322
353
  enabled: boolean;
323
354
  }
324
355
  export type PoseSetEnabledResponse = EmptyResponse;
@@ -343,6 +374,7 @@ export interface TrackingAddSourceRequest {
343
374
  * ifacialmocap: the receive port, default 49983 (set the phone's Send Port to match).
344
375
  */
345
376
  port?: number;
377
+ mediapipe?: Partial<MediaPipeConfig>;
346
378
  }
347
379
  export interface TrackingAddSourceResponse {
348
380
  source: TrackingSourceConfig;
@@ -353,6 +385,7 @@ export interface TrackingUpdateSourceRequest {
353
385
  enabled?: boolean;
354
386
  phoneIp?: string | null;
355
387
  port?: number;
388
+ mediapipe?: Partial<MediaPipeConfig>;
356
389
  }
357
390
  export interface TrackingUpdateSourceResponse {
358
391
  source: TrackingSourceConfig;
@@ -363,7 +396,9 @@ export interface TrackingRemoveSourceRequest {
363
396
  export type TrackingRemoveSourceResponse = EmptyResponse;
364
397
  export type TrackingStatusRequest = EmptyRequest;
365
398
  export interface TrackingStatusResponse {
399
+ /** Aggregate network face status. Webcam activity is reported in sources. */
366
400
  tracking: TrackingStatus;
401
+ /** Aggregate network body status. Webcam activity is reported in sources. */
367
402
  pose: PoseStatus;
368
403
  /** Per-source status by {@link TrackingSourceConfig.id}. */
369
404
  sources: Record<string, TrackingStatus>;
@@ -374,8 +409,6 @@ export interface StageResetTransformRequest {
374
409
  export type StageResetTransformResponse = EmptyResponse;
375
410
  export type StageResetCameraRequest = EmptyRequest;
376
411
  export type StageResetCameraResponse = EmptyResponse;
377
- export type StageShockwaveRequest = EmptyRequest;
378
- export type StageShockwaveResponse = EmptyResponse;
379
412
  export type AppInfoRequest = EmptyRequest;
380
413
  export interface AppInfoResponse {
381
414
  name: string;
@@ -567,6 +600,26 @@ export interface MethodMap {
567
600
  request: InstanceSetBreathRequest;
568
601
  response: InstanceSetBreathResponse;
569
602
  };
603
+ 'instance.setLipSync': {
604
+ request: InstanceSetLipSyncRequest;
605
+ response: InstanceSetLipSyncResponse;
606
+ };
607
+ 'lipSync.state': {
608
+ request: LipSyncStateRequest;
609
+ response: LipSyncStateResponse;
610
+ };
611
+ 'lipSync.configure': {
612
+ request: LipSyncConfigureRequest;
613
+ response: LipSyncConfigureResponse;
614
+ };
615
+ 'lipSync.restart': {
616
+ request: LipSyncRestartRequest;
617
+ response: LipSyncRestartResponse;
618
+ };
619
+ 'lipSync.calibrate': {
620
+ request: LipSyncCalibrateRequest;
621
+ response: LipSyncCalibrateResponse;
622
+ };
570
623
  'controller.state': {
571
624
  request: ControllerStateRequest;
572
625
  response: ControllerStateResponse;
@@ -650,6 +703,10 @@ export interface MethodMap {
650
703
  request: InstanceSetVisibleRequest;
651
704
  response: InstanceSetVisibleResponse;
652
705
  };
706
+ 'instance.setEffects': {
707
+ request: InstanceSetEffectsRequest;
708
+ response: InstanceSetEffectsResponse;
709
+ };
653
710
  /** Bind this instance's face/pose channels to tracking sources (null stops tracking that channel). */
654
711
  'instance.setTrackingSources': {
655
712
  request: InstanceSetTrackingSourcesRequest;
@@ -864,10 +921,6 @@ export interface MethodMap {
864
921
  request: StageResetCameraRequest;
865
922
  response: StageResetCameraResponse;
866
923
  };
867
- 'stage.shockwave': {
868
- request: StageShockwaveRequest;
869
- response: StageShockwaveResponse;
870
- };
871
924
  'app.info': {
872
925
  request: AppInfoRequest;
873
926
  response: AppInfoResponse;
@@ -1,6 +1,6 @@
1
1
  import type { InjectTarget } from './types.ts';
2
2
  /** Bumped on breaking wire changes; the server reports it in `hello` and clients warn on mismatch. */
3
- export declare const PROTOCOL_VERSION = 1;
3
+ export declare const PROTOCOL_VERSION = 3;
4
4
  /** Default port the Persona API server listens on (user-configurable in the app). */
5
5
  export declare const DEFAULT_API_PORT = 25034;
6
6
  /** Default host clients dial: the server binds loopback unless LAN is opted in. */
@@ -1,5 +1,5 @@
1
1
  /** Bumped on breaking wire changes; the server reports it in `hello` and clients warn on mismatch. */
2
- export const PROTOCOL_VERSION = 1;
2
+ export const PROTOCOL_VERSION = 3;
3
3
  /** Default port the Persona API server listens on (user-configurable in the app). */
4
4
  export const DEFAULT_API_PORT = 25034;
5
5
  /** Default host clients dial: the server binds loopback unless LAN is opted in. */
@@ -22,6 +22,13 @@ export declare const InjectEntrySchema: z.ZodObject<{
22
22
  weight: z.ZodOptional<z.ZodNumber>;
23
23
  }, z.core.$strip>;
24
24
  export declare const SettingsPatchSchema: z.ZodObject<{
25
+ lipSync: z.ZodOptional<z.ZodObject<{
26
+ enabled: z.ZodOptional<z.ZodBoolean>;
27
+ deviceId: z.ZodOptional<z.ZodString>;
28
+ gain: z.ZodOptional<z.ZodNumber>;
29
+ noiseGate: z.ZodOptional<z.ZodNumber>;
30
+ smoothing: z.ZodOptional<z.ZodNumber>;
31
+ }, z.core.$strip>>;
25
32
  controller: z.ZodOptional<z.ZodObject<{
26
33
  enabled: z.ZodOptional<z.ZodBoolean>;
27
34
  }, z.core.$strip>>;
@@ -36,9 +43,9 @@ export declare const SettingsPatchSchema: z.ZodObject<{
36
43
  fpsLimit: z.ZodOptional<z.ZodNumber>;
37
44
  selectionOutline: z.ZodOptional<z.ZodBoolean>;
38
45
  effectsQuality: z.ZodOptional<z.ZodEnum<{
39
- high: "high";
40
46
  low: "low";
41
47
  medium: "medium";
48
+ high: "high";
42
49
  }>>;
43
50
  renderScale: z.ZodOptional<z.ZodNumber>;
44
51
  live2dEngine: z.ZodOptional<z.ZodEnum<{
@@ -48,6 +55,42 @@ export declare const SettingsPatchSchema: z.ZodObject<{
48
55
  }, z.core.$strip>>;
49
56
  }, z.core.$strip>;
50
57
  export declare const requestSchemas: {
58
+ 'lipSync.state': z.ZodObject<{}, z.core.$strip>;
59
+ 'lipSync.configure': z.ZodObject<{
60
+ enabled: z.ZodOptional<z.ZodBoolean>;
61
+ deviceId: z.ZodOptional<z.ZodString>;
62
+ gain: z.ZodOptional<z.ZodNumber>;
63
+ noiseGate: z.ZodOptional<z.ZodNumber>;
64
+ smoothing: z.ZodOptional<z.ZodNumber>;
65
+ }, z.core.$strip>;
66
+ 'lipSync.restart': z.ZodObject<{}, z.core.$strip>;
67
+ 'lipSync.calibrate': z.ZodDiscriminatedUnion<[z.ZodObject<{
68
+ action: z.ZodEnum<{
69
+ start: "start";
70
+ cancel: "cancel";
71
+ preview: "preview";
72
+ save: "save";
73
+ reset: "reset";
74
+ }>;
75
+ }, z.core.$strip>, z.ZodObject<{
76
+ action: z.ZodLiteral<"record">;
77
+ phoneme: z.ZodEnum<{
78
+ A: "A";
79
+ I: "I";
80
+ U: "U";
81
+ E: "E";
82
+ O: "O";
83
+ S: "S";
84
+ }>;
85
+ }, z.core.$strip>], "action">;
86
+ 'instance.setLipSync': z.ZodObject<{
87
+ instanceId: z.ZodOptional<z.ZodString>;
88
+ mode: z.ZodEnum<{
89
+ off: "off";
90
+ always: "always";
91
+ "when-untracked": "when-untracked";
92
+ }>;
93
+ }, z.core.$strip>;
51
94
  'registry.thumbnail': z.ZodObject<{
52
95
  kind: z.ZodEnum<{
53
96
  model: "model";
@@ -131,10 +174,22 @@ export declare const requestSchemas: {
131
174
  "vts-ios": "vts-ios";
132
175
  vmc: "vmc";
133
176
  mocopi: "mocopi";
177
+ mediapipe: "mediapipe";
134
178
  }>;
135
179
  name: z.ZodOptional<z.ZodString>;
136
180
  phoneIp: z.ZodOptional<z.ZodNullable<z.ZodString>>;
137
181
  port: z.ZodOptional<z.ZodNumber>;
182
+ mediapipe: z.ZodOptional<z.ZodObject<{
183
+ deviceId: z.ZodOptional<z.ZodString>;
184
+ mirror: z.ZodOptional<z.ZodBoolean>;
185
+ face: z.ZodOptional<z.ZodBoolean>;
186
+ hands: z.ZodOptional<z.ZodBoolean>;
187
+ body: z.ZodOptional<z.ZodBoolean>;
188
+ delegate: z.ZodOptional<z.ZodEnum<{
189
+ CPU: "CPU";
190
+ GPU: "GPU";
191
+ }>>;
192
+ }, z.core.$strip>>;
138
193
  }, z.core.$strip>;
139
194
  'tracking.updateSource': z.ZodObject<{
140
195
  id: z.ZodString;
@@ -142,6 +197,17 @@ export declare const requestSchemas: {
142
197
  enabled: z.ZodOptional<z.ZodBoolean>;
143
198
  phoneIp: z.ZodOptional<z.ZodNullable<z.ZodString>>;
144
199
  port: z.ZodOptional<z.ZodNumber>;
200
+ mediapipe: z.ZodOptional<z.ZodObject<{
201
+ deviceId: z.ZodOptional<z.ZodString>;
202
+ mirror: z.ZodOptional<z.ZodBoolean>;
203
+ face: z.ZodOptional<z.ZodBoolean>;
204
+ hands: z.ZodOptional<z.ZodBoolean>;
205
+ body: z.ZodOptional<z.ZodBoolean>;
206
+ delegate: z.ZodOptional<z.ZodEnum<{
207
+ CPU: "CPU";
208
+ GPU: "GPU";
209
+ }>>;
210
+ }, z.core.$strip>>;
145
211
  }, z.core.$strip>;
146
212
  'tracking.removeSource': z.ZodObject<{
147
213
  id: z.ZodString;
@@ -152,17 +218,24 @@ export declare const requestSchemas: {
152
218
  'asset.register': z.ZodObject<{
153
219
  path: z.ZodString;
154
220
  want: z.ZodOptional<z.ZodEnum<{
155
- lut: "lut";
156
221
  image: "image";
157
222
  video: "video";
158
223
  prop: "prop";
159
224
  ibl: "ibl";
225
+ lut: "lut";
160
226
  animation: "animation";
161
227
  cameraMotion: "cameraMotion";
162
228
  }>>;
163
229
  }, z.core.$strip>;
164
230
  'settings.patch': z.ZodObject<{
165
231
  settings: z.ZodObject<{
232
+ lipSync: z.ZodOptional<z.ZodObject<{
233
+ enabled: z.ZodOptional<z.ZodBoolean>;
234
+ deviceId: z.ZodOptional<z.ZodString>;
235
+ gain: z.ZodOptional<z.ZodNumber>;
236
+ noiseGate: z.ZodOptional<z.ZodNumber>;
237
+ smoothing: z.ZodOptional<z.ZodNumber>;
238
+ }, z.core.$strip>>;
166
239
  controller: z.ZodOptional<z.ZodObject<{
167
240
  enabled: z.ZodOptional<z.ZodBoolean>;
168
241
  }, z.core.$strip>>;
@@ -177,9 +250,9 @@ export declare const requestSchemas: {
177
250
  fpsLimit: z.ZodOptional<z.ZodNumber>;
178
251
  selectionOutline: z.ZodOptional<z.ZodBoolean>;
179
252
  effectsQuality: z.ZodOptional<z.ZodEnum<{
180
- high: "high";
181
253
  low: "low";
182
254
  medium: "medium";
255
+ high: "high";
183
256
  }>>;
184
257
  renderScale: z.ZodOptional<z.ZodNumber>;
185
258
  live2dEngine: z.ZodOptional<z.ZodEnum<{