@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.
- package/README.md +3 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/values/effect-schema.d.ts +71 -11
- package/dist/values/effect-schema.js +278 -65
- package/dist/values/hands.d.ts +53 -0
- package/dist/values/hands.js +89 -0
- package/dist/values/lipsync.d.ts +106 -0
- package/dist/values/lipsync.js +120 -0
- package/dist/wire/events.d.ts +1 -1
- package/dist/wire/methods.d.ts +60 -7
- package/dist/wire/protocol.d.ts +1 -1
- package/dist/wire/protocol.js +1 -1
- package/dist/wire/schemas.d.ts +76 -3
- package/dist/wire/schemas.js +28 -0
- package/dist/wire/types.d.ts +245 -83
- package/dist/wire/types.js +55 -5
- package/package.json +2 -2
|
@@ -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
|
+
}
|
package/dist/wire/events.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export interface EventMap {
|
|
|
14
14
|
'shortcut.state': {
|
|
15
15
|
shortcuts: ShortcutInfo[];
|
|
16
16
|
};
|
|
17
|
-
/** `sources`
|
|
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;
|
package/dist/wire/methods.d.ts
CHANGED
|
@@ -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;
|
package/dist/wire/protocol.d.ts
CHANGED
|
@@ -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 =
|
|
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. */
|
package/dist/wire/protocol.js
CHANGED
|
@@ -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 =
|
|
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. */
|
package/dist/wire/schemas.d.ts
CHANGED
|
@@ -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<{
|