@laplace.live/persona-sdk 0.0.1

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,189 @@
1
+ import * as z from 'zod';
2
+ import type { MethodName } from './methods.ts';
3
+ import type { HotkeyConfig, ObjectContent } from './types.ts';
4
+ export declare const InjectTargetSchema: z.ZodObject<{
5
+ type: z.ZodEnum<{
6
+ input: "input";
7
+ "live2d-param": "live2d-param";
8
+ "vrm-expression": "vrm-expression";
9
+ }>;
10
+ id: z.ZodString;
11
+ instanceId: z.ZodOptional<z.ZodString>;
12
+ }, z.core.$strip>;
13
+ export declare const InjectEntrySchema: z.ZodObject<{
14
+ type: z.ZodEnum<{
15
+ input: "input";
16
+ "live2d-param": "live2d-param";
17
+ "vrm-expression": "vrm-expression";
18
+ }>;
19
+ id: z.ZodString;
20
+ instanceId: z.ZodOptional<z.ZodString>;
21
+ value: z.ZodNumber;
22
+ weight: z.ZodOptional<z.ZodNumber>;
23
+ }, z.core.$strip>;
24
+ export declare const SettingsPatchSchema: z.ZodObject<{
25
+ window: z.ZodOptional<z.ZodObject<{
26
+ alwaysOnTop: z.ZodOptional<z.ZodBoolean>;
27
+ }, z.core.$strip>>;
28
+ ui: z.ZodOptional<z.ZodObject<{
29
+ trayVisible: z.ZodOptional<z.ZodBoolean>;
30
+ }, z.core.$strip>>;
31
+ performance: z.ZodOptional<z.ZodObject<{
32
+ backgroundRendering: z.ZodOptional<z.ZodBoolean>;
33
+ showFps: z.ZodOptional<z.ZodBoolean>;
34
+ fpsLimit: z.ZodOptional<z.ZodNumber>;
35
+ selectionOutline: z.ZodOptional<z.ZodBoolean>;
36
+ effectsQuality: z.ZodOptional<z.ZodEnum<{
37
+ high: "high";
38
+ medium: "medium";
39
+ low: "low";
40
+ }>>;
41
+ }, z.core.$strip>>;
42
+ }, z.core.$strip>;
43
+ export declare const requestSchemas: {
44
+ 'scene.get': z.ZodObject<{
45
+ sceneId: z.ZodOptional<z.ZodString>;
46
+ }, z.core.$strip>;
47
+ 'scene.activate': z.ZodObject<{
48
+ sceneId: z.ZodString;
49
+ }, z.core.$strip>;
50
+ 'scene.duplicate': z.ZodObject<{
51
+ sceneId: z.ZodString;
52
+ }, z.core.$strip>;
53
+ 'scene.rename': z.ZodObject<{
54
+ sceneId: z.ZodString;
55
+ name: z.ZodString;
56
+ }, z.core.$strip>;
57
+ 'scene.delete': z.ZodObject<{
58
+ sceneId: z.ZodString;
59
+ }, z.core.$strip>;
60
+ 'scene.setShortcut': z.ZodObject<{
61
+ sceneId: z.ZodString;
62
+ accelerator: z.ZodNullable<z.ZodString>;
63
+ }, z.core.$strip>;
64
+ 'instance.add': z.ZodObject<{
65
+ modelId: z.ZodString;
66
+ }, z.core.$strip>;
67
+ 'object.add': z.ZodObject<{
68
+ content: z.ZodCustom<ObjectContent, ObjectContent>;
69
+ name: z.ZodOptional<z.ZodString>;
70
+ }, z.core.$strip>;
71
+ 'object.setContent': z.ZodObject<{
72
+ instanceId: z.ZodString;
73
+ content: z.ZodCustom<ObjectContent, ObjectContent>;
74
+ }, z.core.$strip>;
75
+ 'expression.getPersistence': z.ZodObject<{
76
+ modelId: z.ZodOptional<z.ZodString>;
77
+ }, z.core.$strip>;
78
+ 'expression.setPersistence': z.ZodObject<{
79
+ modelId: z.ZodOptional<z.ZodString>;
80
+ enabled: z.ZodBoolean;
81
+ }, z.core.$strip>;
82
+ 'hotkey.list': z.ZodObject<{
83
+ modelId: z.ZodOptional<z.ZodString>;
84
+ }, z.core.$strip>;
85
+ 'hotkey.set': z.ZodObject<{
86
+ modelId: z.ZodOptional<z.ZodString>;
87
+ config: z.ZodCustom<HotkeyConfig, HotkeyConfig>;
88
+ }, z.core.$strip>;
89
+ 'hotkey.trigger': z.ZodObject<{
90
+ hotkeyId: z.ZodString;
91
+ }, z.core.$strip>;
92
+ 'model.register': z.ZodObject<{
93
+ path: z.ZodString;
94
+ }, z.core.$strip>;
95
+ 'asset.register': z.ZodObject<{
96
+ path: z.ZodString;
97
+ want: z.ZodOptional<z.ZodEnum<{
98
+ image: "image";
99
+ video: "video";
100
+ prop: "prop";
101
+ ibl: "ibl";
102
+ lut: "lut";
103
+ }>>;
104
+ }, z.core.$strip>;
105
+ 'settings.patch': z.ZodObject<{
106
+ settings: z.ZodObject<{
107
+ window: z.ZodOptional<z.ZodObject<{
108
+ alwaysOnTop: z.ZodOptional<z.ZodBoolean>;
109
+ }, z.core.$strip>>;
110
+ ui: z.ZodOptional<z.ZodObject<{
111
+ trayVisible: z.ZodOptional<z.ZodBoolean>;
112
+ }, z.core.$strip>>;
113
+ performance: z.ZodOptional<z.ZodObject<{
114
+ backgroundRendering: z.ZodOptional<z.ZodBoolean>;
115
+ showFps: z.ZodOptional<z.ZodBoolean>;
116
+ fpsLimit: z.ZodOptional<z.ZodNumber>;
117
+ selectionOutline: z.ZodOptional<z.ZodBoolean>;
118
+ effectsQuality: z.ZodOptional<z.ZodEnum<{
119
+ high: "high";
120
+ medium: "medium";
121
+ low: "low";
122
+ }>>;
123
+ }, z.core.$strip>>;
124
+ }, z.core.$strip>;
125
+ }, z.core.$strip>;
126
+ 'tracking.setEnabled': z.ZodObject<{
127
+ enabled: z.ZodBoolean;
128
+ }, z.core.$strip>;
129
+ 'tracking.setSource': z.ZodObject<{
130
+ source: z.ZodEnum<{
131
+ "vts-ios": "vts-ios";
132
+ "vts-ios-native": "vts-ios-native";
133
+ ifacialmocap: "ifacialmocap";
134
+ }>;
135
+ }, z.core.$strip>;
136
+ 'pose.setEnabled': z.ZodObject<{
137
+ enabled: z.ZodBoolean;
138
+ }, z.core.$strip>;
139
+ 'pose.setSource': z.ZodObject<{
140
+ source: z.ZodEnum<{
141
+ vmc: "vmc";
142
+ }>;
143
+ }, z.core.$strip>;
144
+ 'pose.setPort': z.ZodObject<{
145
+ port: z.ZodNumber;
146
+ }, z.core.$strip>;
147
+ 'events.subscribe': z.ZodObject<{
148
+ events: z.ZodArray<z.ZodCustom<keyof import("./events.ts").EventMap, keyof import("./events.ts").EventMap>>;
149
+ }, z.core.$strip>;
150
+ 'events.unsubscribe': z.ZodObject<{
151
+ events: z.ZodOptional<z.ZodArray<z.ZodCustom<keyof import("./events.ts").EventMap, keyof import("./events.ts").EventMap>>>;
152
+ }, z.core.$strip>;
153
+ 'param.inject': z.ZodObject<{
154
+ entries: z.ZodArray<z.ZodObject<{
155
+ type: z.ZodEnum<{
156
+ input: "input";
157
+ "live2d-param": "live2d-param";
158
+ "vrm-expression": "vrm-expression";
159
+ }>;
160
+ id: z.ZodString;
161
+ instanceId: z.ZodOptional<z.ZodString>;
162
+ value: z.ZodNumber;
163
+ weight: z.ZodOptional<z.ZodNumber>;
164
+ }, z.core.$strip>>;
165
+ }, z.core.$strip>;
166
+ 'param.release': z.ZodObject<{
167
+ targets: z.ZodOptional<z.ZodArray<z.ZodObject<{
168
+ type: z.ZodEnum<{
169
+ input: "input";
170
+ "live2d-param": "live2d-param";
171
+ "vrm-expression": "vrm-expression";
172
+ }>;
173
+ id: z.ZodString;
174
+ instanceId: z.ZodOptional<z.ZodString>;
175
+ }, z.core.$strip>>>;
176
+ }, z.core.$strip>;
177
+ };
178
+ /**
179
+ * Validate one request's params against its method schema. Methods without a
180
+ * schema pass through verbatim (the stage validates them). On success `params`
181
+ * is the parsed value — unknown keys stripped, ready to hand to an executor.
182
+ */
183
+ export declare function parseRequest(method: MethodName, params: unknown): {
184
+ ok: true;
185
+ params: unknown;
186
+ } | {
187
+ ok: false;
188
+ message: string;
189
+ };
@@ -0,0 +1,92 @@
1
+ import * as z from 'zod';
2
+ import { isEventName } from "./events.js";
3
+ // Runtime validation for the request side of the wire. Schemas exist for the
4
+ // methods whose params the app's main process consumes directly; methods without
5
+ // one are stage-owned — the renderer validates and heals them (same rules as the
6
+ // panel). Fields marked z.custom are deliberately gated shallowly here because
7
+ // the app heals them into shape server-side.
8
+ function isRecord(v) {
9
+ return typeof v === 'object' && v !== null && !Array.isArray(v);
10
+ }
11
+ const nonEmpty = z.string().min(1);
12
+ export const InjectTargetSchema = z.object({
13
+ type: z.enum(['input', 'live2d-param', 'vrm-expression']),
14
+ id: nonEmpty,
15
+ instanceId: nonEmpty.optional(),
16
+ });
17
+ export const InjectEntrySchema = InjectTargetSchema.extend({
18
+ value: z.number(),
19
+ weight: z.number().min(0).max(1).optional(),
20
+ });
21
+ export const SettingsPatchSchema = z.object({
22
+ window: z.object({ alwaysOnTop: z.boolean().optional() }).optional(),
23
+ ui: z.object({ trayVisible: z.boolean().optional() }).optional(),
24
+ performance: z
25
+ .object({
26
+ backgroundRendering: z.boolean().optional(),
27
+ showFps: z.boolean().optional(),
28
+ fpsLimit: z.number().optional(),
29
+ selectionOutline: z.boolean().optional(),
30
+ effectsQuality: z.enum(['high', 'medium', 'low']).optional(),
31
+ })
32
+ .optional(),
33
+ });
34
+ const eventNameSchema = z.custom(isEventName, 'unknown event name');
35
+ /** Tolerates unknown names (version skew); the server ignores what it cannot map. */
36
+ const lenientEventNameSchema = z.custom(v => typeof v === 'string', 'event names must be strings');
37
+ export const requestSchemas = {
38
+ 'scene.get': z.object({ sceneId: nonEmpty.optional() }),
39
+ 'scene.activate': z.object({ sceneId: nonEmpty }),
40
+ 'scene.duplicate': z.object({ sceneId: nonEmpty }),
41
+ 'scene.rename': z.object({ sceneId: nonEmpty, name: nonEmpty }),
42
+ 'scene.delete': z.object({ sceneId: nonEmpty }),
43
+ 'scene.setShortcut': z.object({ sceneId: nonEmpty, accelerator: nonEmpty.nullable() }),
44
+ 'instance.add': z.object({ modelId: nonEmpty }),
45
+ 'object.add': z.object({
46
+ content: z.custom(isRecord, 'content must be an object'),
47
+ name: nonEmpty.optional(),
48
+ }),
49
+ 'object.setContent': z.object({
50
+ instanceId: nonEmpty,
51
+ content: z.custom(isRecord, 'content must be an object'),
52
+ }),
53
+ 'expression.getPersistence': z.object({ modelId: nonEmpty.optional() }),
54
+ 'expression.setPersistence': z.object({ modelId: nonEmpty.optional(), enabled: z.boolean() }),
55
+ 'hotkey.list': z.object({ modelId: nonEmpty.optional() }),
56
+ 'hotkey.set': z.object({
57
+ modelId: nonEmpty.optional(),
58
+ config: z.custom(isRecord, 'config must be a hotkey config'),
59
+ }),
60
+ 'hotkey.trigger': z.object({ hotkeyId: nonEmpty }),
61
+ 'model.register': z.object({ path: nonEmpty }),
62
+ 'asset.register': z.object({ path: nonEmpty, want: z.enum(['image', 'video', 'prop', 'ibl', 'lut']).optional() }),
63
+ 'settings.patch': z.object({ settings: SettingsPatchSchema }),
64
+ 'tracking.setEnabled': z.object({ enabled: z.boolean() }),
65
+ 'tracking.setSource': z.object({ source: z.enum(['vts-ios', 'vts-ios-native', 'ifacialmocap']) }),
66
+ 'pose.setEnabled': z.object({ enabled: z.boolean() }),
67
+ 'pose.setSource': z.object({ source: z.enum(['vmc']) }),
68
+ 'pose.setPort': z.object({ port: z.number().int().min(1).max(65535) }),
69
+ 'events.subscribe': z.object({ events: z.array(eventNameSchema).min(1) }),
70
+ 'events.unsubscribe': z.object({ events: z.array(lenientEventNameSchema).optional() }),
71
+ 'param.inject': z.object({ entries: z.array(InjectEntrySchema).min(1) }),
72
+ 'param.release': z.object({ targets: z.array(InjectTargetSchema).optional() }),
73
+ };
74
+ /**
75
+ * Validate one request's params against its method schema. Methods without a
76
+ * schema pass through verbatim (the stage validates them). On success `params`
77
+ * is the parsed value — unknown keys stripped, ready to hand to an executor.
78
+ */
79
+ export function parseRequest(method, params) {
80
+ if (!Object.hasOwn(requestSchemas, method))
81
+ return { ok: true, params };
82
+ const schema = requestSchemas[method];
83
+ if (schema === undefined)
84
+ return { ok: true, params };
85
+ const r = schema.safeParse(params);
86
+ if (r.success)
87
+ return { ok: true, params: r.data };
88
+ const issue = r.error.issues[0];
89
+ const path = issue === undefined ? '' : issue.path.map(String).join('.');
90
+ const message = issue?.message ?? 'params do not match the method schema';
91
+ return { ok: false, message: path === '' ? message : `${path}: ${message}` };
92
+ }
@@ -0,0 +1,390 @@
1
+ export type ModelFormat = 'live2d' | 'vrm';
2
+ export type ModelKind = 'bundled' | 'user';
3
+ /** A model as the registry lists it. Paths deliberately never cross the wire. */
4
+ export interface ModelRef {
5
+ id: string;
6
+ name: string;
7
+ kind: ModelKind;
8
+ format: ModelFormat;
9
+ }
10
+ export type AssetKind = 'image' | 'video' | 'prop' | 'ibl' | 'lut';
11
+ /** A registered object-source file. `exists` is false once the file is gone from disk. */
12
+ export interface AssetRef {
13
+ id: string;
14
+ name: string;
15
+ kind: AssetKind;
16
+ exists: boolean;
17
+ }
18
+ /** Screen-space placement: pixels from the stage centre, rotation in radians. */
19
+ export interface ScreenPlacement {
20
+ x: number;
21
+ y: number;
22
+ scale: number;
23
+ rotation: number;
24
+ }
25
+ /** World-space VRM placement. Rotations in radians. */
26
+ export interface VrmPlacement {
27
+ x: number;
28
+ y: number;
29
+ z: number;
30
+ rotX: number;
31
+ rotY: number;
32
+ rotZ: number;
33
+ scale: number;
34
+ }
35
+ export interface Place2D extends ScreenPlacement {
36
+ opacity: number;
37
+ }
38
+ export interface Place3D extends VrmPlacement {
39
+ opacity: number;
40
+ }
41
+ /** Per-instance MToon fine-tuning, layered over each material's authored values. */
42
+ export interface MToonTuning {
43
+ shade: number;
44
+ shadingShift: number;
45
+ shadingToony: number;
46
+ giEqualization: number;
47
+ rim: number;
48
+ outlineWidth: number;
49
+ emissive: number;
50
+ }
51
+ export interface SceneModelItem {
52
+ kind: 'model';
53
+ instanceId: string;
54
+ ref: ModelRef;
55
+ visible: boolean;
56
+ live2d: ScreenPlacement;
57
+ vrm: VrmPlacement;
58
+ idleAnimation: boolean;
59
+ idleClip: string;
60
+ mtoon: MToonTuning;
61
+ }
62
+ export type ObjectSpace = '2d' | '3d';
63
+ export type WebLayer = 'behind' | 'front';
64
+ export type CaptureKind = 'display' | 'window';
65
+ export type ObjectContent = {
66
+ kind: 'image';
67
+ assetId: string;
68
+ } | {
69
+ kind: 'video';
70
+ assetId: string;
71
+ loop: boolean;
72
+ muted: boolean;
73
+ volume: number;
74
+ } | {
75
+ kind: 'prop';
76
+ assetId: string;
77
+ } | {
78
+ kind: 'web';
79
+ url: string;
80
+ width: number;
81
+ height: number;
82
+ fps: number;
83
+ transparent: boolean;
84
+ css: string;
85
+ layer: WebLayer;
86
+ } | {
87
+ kind: 'capture';
88
+ source: CaptureKind;
89
+ sourceId: string;
90
+ label: string;
91
+ };
92
+ /** Where on a parent model an object rides. */
93
+ export type AttachAnchor = {
94
+ kind: 'root';
95
+ } | {
96
+ kind: 'bone';
97
+ bone: string;
98
+ } | {
99
+ kind: 'artMesh';
100
+ id: string;
101
+ verts: [number, number, number];
102
+ weights: [number, number, number];
103
+ };
104
+ export interface Attach {
105
+ parentInstanceId: string;
106
+ anchor: AttachAnchor;
107
+ followRotation: boolean;
108
+ headAngle: {
109
+ multiplier: number;
110
+ smoothing: number;
111
+ } | null;
112
+ elasticity: {
113
+ stiffness: number;
114
+ damping: number;
115
+ maxSpeed: number;
116
+ } | null;
117
+ }
118
+ export interface ObjectLightOverride {
119
+ enabled: boolean;
120
+ intensity: number | null;
121
+ }
122
+ export interface SceneObjectItem {
123
+ kind: 'object';
124
+ instanceId: string;
125
+ name: string;
126
+ visible: boolean;
127
+ space: ObjectSpace;
128
+ content: ObjectContent;
129
+ place2d: Place2D;
130
+ place3d: Place3D;
131
+ attach: Attach | null;
132
+ lightOverrides: Record<string, ObjectLightOverride>;
133
+ }
134
+ export type SceneItem = SceneModelItem | SceneObjectItem;
135
+ export type BackgroundMode = 'transparent' | 'color' | 'image';
136
+ /** `imagePath` is accepted but survives only when the app has allowlisted it via its own picker. */
137
+ export interface SceneBackground {
138
+ mode: BackgroundMode;
139
+ color: string;
140
+ imagePath: string | null;
141
+ }
142
+ export interface SceneBehavior {
143
+ lookAtCursor: boolean;
144
+ }
145
+ export interface OrbitTransform {
146
+ azimuth: number;
147
+ elevation: number;
148
+ distance: number;
149
+ targetX: number;
150
+ targetY: number;
151
+ }
152
+ export interface SceneCamera {
153
+ orbit: OrbitTransform | null;
154
+ fov: number;
155
+ }
156
+ export type SceneLightType = 'directional' | 'point' | 'ambient';
157
+ export interface SceneLight {
158
+ id: string;
159
+ type: SceneLightType;
160
+ color: string;
161
+ intensity: number;
162
+ azimuth: number;
163
+ elevation: number;
164
+ x: number;
165
+ y: number;
166
+ z: number;
167
+ range: number;
168
+ castShadow: boolean;
169
+ shadowRadius: number;
170
+ }
171
+ export interface SceneFog {
172
+ enabled: boolean;
173
+ color: string;
174
+ density: number;
175
+ }
176
+ export type SceneToneMapping = 'none' | 'neutral' | 'aces' | 'agx';
177
+ export interface SceneEffects {
178
+ toneMapping: SceneToneMapping;
179
+ exposure: number;
180
+ bloom: {
181
+ enabled: boolean;
182
+ intensity: number;
183
+ threshold: number;
184
+ radius: number;
185
+ };
186
+ vignette: {
187
+ enabled: boolean;
188
+ darkness: number;
189
+ offset: number;
190
+ };
191
+ color: {
192
+ enabled: boolean;
193
+ hue: number;
194
+ saturation: number;
195
+ brightness: number;
196
+ contrast: number;
197
+ };
198
+ chromaticAberration: {
199
+ enabled: boolean;
200
+ strength: number;
201
+ };
202
+ grain: {
203
+ enabled: boolean;
204
+ strength: number;
205
+ };
206
+ lut: {
207
+ assetId: string | null;
208
+ intensity: number;
209
+ };
210
+ dof: {
211
+ enabled: boolean;
212
+ bokehScale: number;
213
+ focusRange: number;
214
+ };
215
+ stylize: {
216
+ pixelate: {
217
+ enabled: boolean;
218
+ granularity: number;
219
+ };
220
+ glitch: {
221
+ enabled: boolean;
222
+ };
223
+ };
224
+ }
225
+ export interface SceneEnvironment {
226
+ iblAssetId: string | null;
227
+ iblIntensity: number;
228
+ showSkybox: boolean;
229
+ fog: SceneFog;
230
+ effects: SceneEffects;
231
+ }
232
+ export interface Scene {
233
+ id: string;
234
+ name: string;
235
+ items: SceneItem[];
236
+ primaryInstanceId: string | null;
237
+ background: SceneBackground;
238
+ behavior: SceneBehavior;
239
+ vrmCamera: SceneCamera;
240
+ lights: SceneLight[];
241
+ environment: SceneEnvironment;
242
+ shortcut: string | null;
243
+ }
244
+ export interface SceneState {
245
+ scenes: Scene[];
246
+ activeSceneId: string;
247
+ /** Scene ids whose shortcut is currently registered with the OS. */
248
+ registeredSceneIds: string[];
249
+ }
250
+ /**
251
+ * Editable sections of the active scene. Items are deliberately absent — they
252
+ * are manipulated through `instance.*` / `object.*` methods so the app, not the
253
+ * client, constructs model refs and asset references.
254
+ */
255
+ export interface ScenePatch {
256
+ background?: SceneBackground;
257
+ behavior?: SceneBehavior;
258
+ vrmCamera?: SceneCamera;
259
+ lights?: SceneLight[];
260
+ environment?: SceneEnvironment;
261
+ }
262
+ /** What a loaded model instance can do; absent capabilities answer `unsupported-for-format`. */
263
+ export type InstanceCapability = 'motions' | 'expressions' | 'placement-2d' | 'placement-3d' | 'mtoon' | 'idle-clips' | 'pose' | 'live2d-params';
264
+ export interface InstanceRuntime {
265
+ instanceId: string;
266
+ kind: 'model' | 'object';
267
+ /** Model format, or null for objects. */
268
+ format: ModelFormat | null;
269
+ loaded: boolean;
270
+ capabilities: InstanceCapability[];
271
+ }
272
+ export interface MotionGroup {
273
+ group: string;
274
+ files: string[];
275
+ }
276
+ export interface Expression {
277
+ name: string;
278
+ file: string | null;
279
+ active: boolean;
280
+ }
281
+ export interface PlayingMotion {
282
+ group: string;
283
+ index: number;
284
+ }
285
+ export interface AnchorOption {
286
+ anchor: AttachAnchor;
287
+ label: string;
288
+ }
289
+ /** Panel-style model info block. Format-specific fields mirror the app's `ModelInfo`. */
290
+ export interface ModelInfo {
291
+ format: ModelFormat;
292
+ name: string;
293
+ kind: ModelKind;
294
+ file: string;
295
+ loadMs: number;
296
+ /** Format-specific details (canvas/params/textures for Live2D, spec/bones for VRM). */
297
+ [key: string]: unknown;
298
+ }
299
+ export interface Hotkey {
300
+ id: string;
301
+ name: string;
302
+ /** The VTS `Action` string verbatim; `action` is null when Persona cannot run it. */
303
+ vtsAction: string;
304
+ action: 'toggle-expression' | 'play-motion' | 'remove-all-expressions' | 'load-model' | null;
305
+ file: string;
306
+ accelerator: string | null;
307
+ global: boolean;
308
+ active: boolean;
309
+ }
310
+ export interface HotkeyConfig {
311
+ keyboardEnabled: boolean;
312
+ hotkeys: Hotkey[];
313
+ }
314
+ export interface HotkeyState extends HotkeyConfig {
315
+ /** Hotkey ids currently registered with the OS (active model only). */
316
+ registered: string[];
317
+ }
318
+ export interface ExpressionPersistence {
319
+ supported: boolean;
320
+ enabled: boolean;
321
+ saved: string[];
322
+ }
323
+ export type TrackingSourceId = 'vts-ios' | 'vts-ios-native' | 'ifacialmocap';
324
+ export type PoseSourceId = 'vmc';
325
+ export type EffectsQuality = 'high' | 'medium' | 'low';
326
+ export type TrackingStatus = 'off' | 'waiting' | 'tracking' | 'no-face';
327
+ export type PoseStatus = 'off' | 'waiting' | 'tracking';
328
+ /** The curated settings surface the API exposes — never the raw store shape. */
329
+ export interface Settings {
330
+ window: {
331
+ alwaysOnTop: boolean;
332
+ };
333
+ ui: {
334
+ trayVisible: boolean;
335
+ };
336
+ performance: {
337
+ backgroundRendering: boolean;
338
+ showFps: boolean;
339
+ fpsLimit: number;
340
+ selectionOutline: boolean;
341
+ effectsQuality: EffectsQuality;
342
+ };
343
+ tracking: {
344
+ enabled: boolean;
345
+ source: TrackingSourceId;
346
+ };
347
+ pose: {
348
+ enabled: boolean;
349
+ source: PoseSourceId;
350
+ port: number;
351
+ };
352
+ }
353
+ export interface SettingsPatch {
354
+ window?: {
355
+ alwaysOnTop?: boolean;
356
+ };
357
+ ui?: {
358
+ trayVisible?: boolean;
359
+ };
360
+ performance?: {
361
+ backgroundRendering?: boolean;
362
+ showFps?: boolean;
363
+ fpsLimit?: number;
364
+ selectionOutline?: boolean;
365
+ effectsQuality?: EffectsQuality;
366
+ };
367
+ }
368
+ /** VTS's input vocabulary — the valid `id`s for `input` inject targets (and the names a model's `.vtube.json` references). */
369
+ export declare const INPUT_NAMES: readonly ["FaceAngleX", "FaceAngleY", "FaceAngleZ", "FacePositionX", "FacePositionY", "FacePositionZ", "EyeOpenLeft", "EyeOpenRight", "EyeLeftX", "EyeLeftY", "EyeRightX", "EyeRightY", "Brows", "BrowLeftY", "BrowRightY", "MouthSmile", "MouthOpen", "MouthX", "CheekPuff", "JawOpen", "TongueOut", "MouthPucker", "MouthFunnel", "MouthShrug", "MouthPress"];
370
+ export type InputName = (typeof INPUT_NAMES)[number];
371
+ /**
372
+ * What an injected value drives:
373
+ * - `input` — a VTS-vocabulary tracking input (`MouthOpen`, `FaceAngleX`, …), mapped
374
+ * through the model's own tracking rules. Live2D only.
375
+ * - `live2d-param` — a Cubism parameter id, written directly.
376
+ * - `vrm-expression` — reserved, not implemented yet; the server answers
377
+ * `unsupported-for-format`.
378
+ */
379
+ export type InjectTargetType = 'input' | 'live2d-param' | 'vrm-expression';
380
+ export interface InjectTarget {
381
+ type: InjectTargetType;
382
+ id: string;
383
+ /** Defaults to the scene's primary model instance. */
384
+ instanceId?: string;
385
+ }
386
+ export interface InjectEntry extends InjectTarget {
387
+ value: number;
388
+ /** 0..1 blend over whatever else drives the parameter; default 1. */
389
+ weight?: number;
390
+ }
package/dist/types.js ADDED
@@ -0,0 +1,32 @@
1
+ // The API's data model: the entity shapes that requests, responses, and events
2
+ // carry. Structural mirrors of the app's scene/settings models, minus anything
3
+ // filesystem-shaped — model refs are sanitized to ids, never directories.
4
+ // ---- Injection -----------------------------------------------------------------
5
+ /** VTS's input vocabulary — the valid `id`s for `input` inject targets (and the names a model's `.vtube.json` references). */
6
+ export const INPUT_NAMES = [
7
+ 'FaceAngleX',
8
+ 'FaceAngleY',
9
+ 'FaceAngleZ',
10
+ 'FacePositionX',
11
+ 'FacePositionY',
12
+ 'FacePositionZ',
13
+ 'EyeOpenLeft',
14
+ 'EyeOpenRight',
15
+ 'EyeLeftX',
16
+ 'EyeLeftY',
17
+ 'EyeRightX',
18
+ 'EyeRightY',
19
+ 'Brows',
20
+ 'BrowLeftY',
21
+ 'BrowRightY',
22
+ 'MouthSmile',
23
+ 'MouthOpen',
24
+ 'MouthX',
25
+ 'CheekPuff',
26
+ 'JawOpen',
27
+ 'TongueOut',
28
+ 'MouthPucker',
29
+ 'MouthFunnel',
30
+ 'MouthShrug',
31
+ 'MouthPress',
32
+ ];