@laplace.live/persona-sdk 0.18.0 → 1.0.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 +1 -1
- package/dist/client/client.d.ts +1 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +7 -1
- package/dist/values/bindings.d.ts +43 -0
- package/dist/values/bindings.js +1 -0
- package/dist/values/controller.d.ts +109 -0
- package/dist/values/controller.js +167 -0
- package/dist/values/curve.d.ts +7 -8
- package/dist/values/curve.js +18 -8
- package/dist/values/edit-history.d.ts +21 -0
- package/dist/values/edit-history.js +62 -0
- package/dist/values/effect-schema.d.ts +2 -2
- package/dist/values/effect-schema.js +1 -2
- package/dist/values/gltf-extensions.d.ts +20 -0
- package/dist/values/gltf-extensions.js +68 -0
- package/dist/values/guards.d.ts +2 -0
- package/dist/values/guards.js +5 -0
- package/dist/values/hotkeys.d.ts +6 -0
- package/dist/values/hotkeys.js +11 -0
- package/dist/values/labels.d.ts +2 -0
- package/dist/values/labels.js +5 -1
- package/dist/values/limits.d.ts +25 -0
- package/dist/values/limits.js +33 -0
- package/dist/values/locale.d.ts +2 -0
- package/dist/values/model-info.d.ts +66 -0
- package/dist/values/model-info.js +1 -0
- package/dist/values/stage-info.d.ts +27 -0
- package/dist/values/stage-info.js +1 -0
- package/dist/values/vrm-bindings.d.ts +14 -0
- package/dist/values/vrm-bindings.js +20 -0
- package/dist/wire/methods.d.ts +151 -5
- package/dist/wire/schemas.d.ts +46 -5
- package/dist/wire/schemas.js +12 -0
- package/dist/wire/types.d.ts +69 -58
- package/dist/wire/types.js +39 -11
- package/package.json +2 -16
- package/dist/effects.d.ts +0 -79
- package/dist/effects.js +0 -6
- package/dist/values/custom-effect.d.ts +0 -44
- package/dist/values/custom-effect.js +0 -136
package/dist/wire/schemas.d.ts
CHANGED
|
@@ -22,6 +22,9 @@ 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
|
+
controller: z.ZodOptional<z.ZodObject<{
|
|
26
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
27
|
+
}, z.core.$strip>>;
|
|
25
28
|
window: z.ZodOptional<z.ZodObject<{
|
|
26
29
|
alwaysOnTop: z.ZodOptional<z.ZodBoolean>;
|
|
27
30
|
}, z.core.$strip>>;
|
|
@@ -33,13 +36,39 @@ export declare const SettingsPatchSchema: z.ZodObject<{
|
|
|
33
36
|
fpsLimit: z.ZodOptional<z.ZodNumber>;
|
|
34
37
|
selectionOutline: z.ZodOptional<z.ZodBoolean>;
|
|
35
38
|
effectsQuality: z.ZodOptional<z.ZodEnum<{
|
|
39
|
+
high: "high";
|
|
36
40
|
low: "low";
|
|
37
41
|
medium: "medium";
|
|
38
|
-
|
|
42
|
+
}>>;
|
|
43
|
+
renderScale: z.ZodOptional<z.ZodNumber>;
|
|
44
|
+
live2dEngine: z.ZodOptional<z.ZodEnum<{
|
|
45
|
+
pixi: "pixi";
|
|
46
|
+
three: "three";
|
|
39
47
|
}>>;
|
|
40
48
|
}, z.core.$strip>>;
|
|
41
49
|
}, z.core.$strip>;
|
|
42
50
|
export declare const requestSchemas: {
|
|
51
|
+
'registry.thumbnail': z.ZodObject<{
|
|
52
|
+
kind: z.ZodEnum<{
|
|
53
|
+
model: "model";
|
|
54
|
+
asset: "asset";
|
|
55
|
+
}>;
|
|
56
|
+
id: z.ZodString;
|
|
57
|
+
}, z.core.$strip>;
|
|
58
|
+
'controller.rename': z.ZodObject<{
|
|
59
|
+
slot: z.ZodNumber;
|
|
60
|
+
name: z.ZodString;
|
|
61
|
+
}, z.core.$strip>;
|
|
62
|
+
'controller.setDeadZone': z.ZodObject<{
|
|
63
|
+
slot: z.ZodNumber;
|
|
64
|
+
deadZone: z.ZodNumber;
|
|
65
|
+
}, z.core.$strip>;
|
|
66
|
+
'controller.remove': z.ZodObject<{
|
|
67
|
+
slot: z.ZodNumber;
|
|
68
|
+
}, z.core.$strip>;
|
|
69
|
+
'controller.assign': z.ZodObject<{
|
|
70
|
+
slot: z.ZodNullable<z.ZodNumber>;
|
|
71
|
+
}, z.core.$strip>;
|
|
43
72
|
'scene.get': z.ZodObject<{
|
|
44
73
|
sceneId: z.ZodOptional<z.ZodString>;
|
|
45
74
|
}, z.core.$strip>;
|
|
@@ -97,9 +126,11 @@ export declare const requestSchemas: {
|
|
|
97
126
|
}, z.core.$strip>;
|
|
98
127
|
'tracking.addSource': z.ZodObject<{
|
|
99
128
|
kind: z.ZodEnum<{
|
|
100
|
-
"
|
|
129
|
+
"persona-ios": "persona-ios";
|
|
101
130
|
ifacialmocap: "ifacialmocap";
|
|
131
|
+
"vts-ios": "vts-ios";
|
|
102
132
|
vmc: "vmc";
|
|
133
|
+
mocopi: "mocopi";
|
|
103
134
|
}>;
|
|
104
135
|
name: z.ZodOptional<z.ZodString>;
|
|
105
136
|
phoneIp: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
@@ -121,17 +152,20 @@ export declare const requestSchemas: {
|
|
|
121
152
|
'asset.register': z.ZodObject<{
|
|
122
153
|
path: z.ZodString;
|
|
123
154
|
want: z.ZodOptional<z.ZodEnum<{
|
|
155
|
+
lut: "lut";
|
|
124
156
|
image: "image";
|
|
125
157
|
video: "video";
|
|
126
158
|
prop: "prop";
|
|
127
159
|
ibl: "ibl";
|
|
128
|
-
lut: "lut";
|
|
129
160
|
animation: "animation";
|
|
130
161
|
cameraMotion: "cameraMotion";
|
|
131
162
|
}>>;
|
|
132
163
|
}, z.core.$strip>;
|
|
133
164
|
'settings.patch': z.ZodObject<{
|
|
134
165
|
settings: z.ZodObject<{
|
|
166
|
+
controller: z.ZodOptional<z.ZodObject<{
|
|
167
|
+
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
168
|
+
}, z.core.$strip>>;
|
|
135
169
|
window: z.ZodOptional<z.ZodObject<{
|
|
136
170
|
alwaysOnTop: z.ZodOptional<z.ZodBoolean>;
|
|
137
171
|
}, z.core.$strip>>;
|
|
@@ -143,9 +177,14 @@ export declare const requestSchemas: {
|
|
|
143
177
|
fpsLimit: z.ZodOptional<z.ZodNumber>;
|
|
144
178
|
selectionOutline: z.ZodOptional<z.ZodBoolean>;
|
|
145
179
|
effectsQuality: z.ZodOptional<z.ZodEnum<{
|
|
180
|
+
high: "high";
|
|
146
181
|
low: "low";
|
|
147
182
|
medium: "medium";
|
|
148
|
-
|
|
183
|
+
}>>;
|
|
184
|
+
renderScale: z.ZodOptional<z.ZodNumber>;
|
|
185
|
+
live2dEngine: z.ZodOptional<z.ZodEnum<{
|
|
186
|
+
pixi: "pixi";
|
|
187
|
+
three: "three";
|
|
149
188
|
}>>;
|
|
150
189
|
}, z.core.$strip>>;
|
|
151
190
|
}, z.core.$strip>;
|
|
@@ -155,8 +194,9 @@ export declare const requestSchemas: {
|
|
|
155
194
|
}, z.core.$strip>;
|
|
156
195
|
'tracking.setSource': z.ZodObject<{
|
|
157
196
|
source: z.ZodEnum<{
|
|
158
|
-
"
|
|
197
|
+
"persona-ios": "persona-ios";
|
|
159
198
|
ifacialmocap: "ifacialmocap";
|
|
199
|
+
"vts-ios": "vts-ios";
|
|
160
200
|
}>;
|
|
161
201
|
}, z.core.$strip>;
|
|
162
202
|
'pose.setEnabled': z.ZodObject<{
|
|
@@ -165,6 +205,7 @@ export declare const requestSchemas: {
|
|
|
165
205
|
'pose.setSource': z.ZodObject<{
|
|
166
206
|
source: z.ZodEnum<{
|
|
167
207
|
vmc: "vmc";
|
|
208
|
+
mocopi: "mocopi";
|
|
168
209
|
}>;
|
|
169
210
|
}, z.core.$strip>;
|
|
170
211
|
'pose.setPort': z.ZodObject<{
|
package/dist/wire/schemas.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import * as z from 'zod';
|
|
2
|
+
import { CONTROLLER_DEAD_ZONE_MAX } from "../values/controller.js";
|
|
2
3
|
import { isRecord } from "../values/guards.js";
|
|
3
4
|
import { SPEECH_URL_MAX_LENGTH, STORAGE_KEY_MAX_LENGTH, STORAGE_VALUE_MAX_LENGTH } from "../values/limits.js";
|
|
4
5
|
import { ASSET_KINDS, POSE_SOURCE_IDS, TRACKING_SOURCE_IDS, TRACKING_SOURCE_KINDS } from "./types.js";
|
|
@@ -19,6 +20,7 @@ export const InjectEntrySchema = InjectTargetSchema.extend({
|
|
|
19
20
|
weight: z.number().min(0).max(1).optional(),
|
|
20
21
|
});
|
|
21
22
|
export const SettingsPatchSchema = z.object({
|
|
23
|
+
controller: z.object({ enabled: z.boolean().optional() }).optional(),
|
|
22
24
|
window: z.object({ alwaysOnTop: z.boolean().optional() }).optional(),
|
|
23
25
|
ui: z.object({ trayVisible: z.boolean().optional() }).optional(),
|
|
24
26
|
performance: z
|
|
@@ -27,6 +29,8 @@ export const SettingsPatchSchema = z.object({
|
|
|
27
29
|
fpsLimit: z.number().optional(),
|
|
28
30
|
selectionOutline: z.boolean().optional(),
|
|
29
31
|
effectsQuality: z.enum(['high', 'medium', 'low']).optional(),
|
|
32
|
+
renderScale: z.number().optional(),
|
|
33
|
+
live2dEngine: z.enum(['pixi', 'three']).optional(),
|
|
30
34
|
})
|
|
31
35
|
.optional(),
|
|
32
36
|
});
|
|
@@ -52,6 +56,14 @@ const speechUrl = z
|
|
|
52
56
|
}
|
|
53
57
|
}, 'url must be http(s) or data:audio/*');
|
|
54
58
|
export const requestSchemas = {
|
|
59
|
+
'registry.thumbnail': z.object({ kind: z.enum(['model', 'asset']), id: nonEmpty }),
|
|
60
|
+
'controller.rename': z.object({ slot: z.number().int().positive(), name: z.string() }),
|
|
61
|
+
'controller.setDeadZone': z.object({
|
|
62
|
+
slot: z.number().int().positive(),
|
|
63
|
+
deadZone: z.number().min(0).max(CONTROLLER_DEAD_ZONE_MAX),
|
|
64
|
+
}),
|
|
65
|
+
'controller.remove': z.object({ slot: z.number().int().positive() }),
|
|
66
|
+
'controller.assign': z.object({ slot: z.number().int().positive().nullable() }),
|
|
55
67
|
'scene.get': z.object({ sceneId: nonEmpty.optional() }),
|
|
56
68
|
'scene.activate': z.object({ sceneId: nonEmpty }),
|
|
57
69
|
'scene.duplicate': z.object({ sceneId: nonEmpty }),
|
package/dist/wire/types.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import type { ControllerConfig } from '../values/controller.ts';
|
|
1
2
|
import { type ArkitInputName } from '../values/arkit.ts';
|
|
3
|
+
import { type BaseControllerInputName, type ControllerInputName, type ControllerMovementConfig } from '../values/controller.ts';
|
|
2
4
|
export type ModelFormat = 'live2d' | 'vrm';
|
|
3
5
|
/** Where an item came from: shipped with the app, or added by the user. */
|
|
4
6
|
export type ContentOrigin = 'bundled' | 'user';
|
|
@@ -44,6 +46,8 @@ export interface AssetRef extends ContentRef {
|
|
|
44
46
|
/** What the extension makes it — an object created from it starts on this kind. */
|
|
45
47
|
kind: AssetKind;
|
|
46
48
|
exists: boolean;
|
|
49
|
+
/** Source basename, with no directory. Absent on older hosts. */
|
|
50
|
+
file?: string;
|
|
47
51
|
}
|
|
48
52
|
/**
|
|
49
53
|
* Content metadata decoupled from any on-disk file — local registry entries and
|
|
@@ -140,8 +144,10 @@ export interface SceneModelItem {
|
|
|
140
144
|
* A dangling or disabled id behaves as null. One source may track several instances (mirroring).
|
|
141
145
|
*/
|
|
142
146
|
faceSourceId: string | null;
|
|
143
|
-
/** Body source
|
|
147
|
+
/** Body source tracking this instance; null = its pose is untracked. New instances bind to each channel's default source. */
|
|
144
148
|
poseSourceId: string | null;
|
|
149
|
+
/** Opt-in controller movement, independent of parameter/bone bindings; disabled by default. */
|
|
150
|
+
controllerMovement: ControllerMovementConfig;
|
|
145
151
|
live2d: ScreenPlacement;
|
|
146
152
|
vrm: VrmPlacement;
|
|
147
153
|
idleAnimation: boolean;
|
|
@@ -175,19 +181,31 @@ export type ObjectContent = {
|
|
|
175
181
|
assetId: string;
|
|
176
182
|
} | {
|
|
177
183
|
kind: 'web';
|
|
184
|
+
/** http(s) only; anything else is dropped on load. Rendered in an isolated in-memory browser session. */
|
|
178
185
|
url: string;
|
|
186
|
+
/** Browser viewport, CSS px. A change reloads the page. */
|
|
179
187
|
width: number;
|
|
180
188
|
height: number;
|
|
189
|
+
/** Paint-rate cap; a static page paints only when it changes regardless. */
|
|
181
190
|
fps: number;
|
|
191
|
+
/** Transparent page background (else white), as an OBS browser source. */
|
|
182
192
|
transparent: boolean;
|
|
193
|
+
/** Stylesheet injected into every page the object loads; empty for none. */
|
|
183
194
|
css: string;
|
|
195
|
+
/** 2D only: composited behind or in front of the whole stage, not interleaved with other layers. */
|
|
184
196
|
layer: WebLayer;
|
|
197
|
+
/** Close the page while the object is hidden and reload it on show, as an OBS browser source can. */
|
|
198
|
+
shutdownWhenHidden: boolean;
|
|
185
199
|
} | {
|
|
186
200
|
kind: 'capture';
|
|
187
201
|
source: CaptureKind;
|
|
188
202
|
sourceId: string;
|
|
189
203
|
label: string;
|
|
190
204
|
};
|
|
205
|
+
/** The webpage variant of {@link ObjectContent}. */
|
|
206
|
+
export type WebContent = Extract<ObjectContent, {
|
|
207
|
+
kind: 'web';
|
|
208
|
+
}>;
|
|
191
209
|
/** Where on a parent model an object rides. `root` is the model's own transform. */
|
|
192
210
|
export type AttachAnchor = {
|
|
193
211
|
kind: 'root';
|
|
@@ -592,24 +610,6 @@ export type ToggleEffectKey = {
|
|
|
592
610
|
enabled: boolean;
|
|
593
611
|
} ? K : never;
|
|
594
612
|
}[keyof SceneEffects];
|
|
595
|
-
/**
|
|
596
|
-
* One user-authored effect's placement in a scene. Deliberately a sibling of
|
|
597
|
-
* {@link SceneEffects} rather than a key inside it: `ToggleEffectKey` is derived
|
|
598
|
-
* from that interface, and healing, defaults, hotkey snapshots and the panel all
|
|
599
|
-
* iterate it as a closed compile-time union. Runtime keys in there would erase
|
|
600
|
-
* that guarantee for the built-in effects too.
|
|
601
|
-
*/
|
|
602
|
-
export interface SceneCustomEffect {
|
|
603
|
-
/** Folder name under the config home's `effects/` dir — stable id and module location. */
|
|
604
|
-
slug: string;
|
|
605
|
-
enabled: boolean;
|
|
606
|
-
/**
|
|
607
|
-
* Author-declared values, keyed by the manifest's param names. Untyped by
|
|
608
|
-
* construction: the specs arrive from disk at runtime, so these are validated
|
|
609
|
-
* against the installed manifest rather than checked at compile time.
|
|
610
|
-
*/
|
|
611
|
-
params: Record<string, number | boolean | string>;
|
|
612
|
-
}
|
|
613
613
|
/**
|
|
614
614
|
* A 3D set's own suggested look — the fog and post settings it was authored against,
|
|
615
615
|
* read from its root `LAPLACE_environment` extension and held on the scene for every client.
|
|
@@ -671,14 +671,6 @@ export interface SceneEnvironment {
|
|
|
671
671
|
* switched off. Healing lists every switched-on effect, so a patch that switches one on adds its layer.
|
|
672
672
|
*/
|
|
673
673
|
effectLayers: ToggleEffectKey[];
|
|
674
|
-
/**
|
|
675
|
-
* User-authored effects, in the order they compose. They run as a group at one
|
|
676
|
-
* fixed point in the post chain — after grading and the screen-space warps,
|
|
677
|
-
* before grain and vignette — so the built-in composition order stays fixed.
|
|
678
|
-
* An entry whose effect is not installed here is kept, not dropped: it would
|
|
679
|
-
* cost the user their tuning on a machine that simply lacks the folder.
|
|
680
|
-
*/
|
|
681
|
-
customEffects: SceneCustomEffect[];
|
|
682
674
|
}
|
|
683
675
|
export interface Scene {
|
|
684
676
|
id: string;
|
|
@@ -718,11 +710,13 @@ export interface ScenePatch {
|
|
|
718
710
|
* App-level features a client gates on (never version-sniff): `hello` and
|
|
719
711
|
* `app.info` report them — the per-app mirror of {@link InstanceRuntime.capabilities}.
|
|
720
712
|
*/
|
|
721
|
-
export declare const APP_CAPABILITIES: readonly ["storage", "speech", "shortcuts"];
|
|
713
|
+
export declare const APP_CAPABILITIES: readonly ["storage", "speech", "shortcuts", "controllers", "model-editing", "asset-inspection"];
|
|
722
714
|
export type AppCapability = (typeof APP_CAPABILITIES)[number];
|
|
723
715
|
export declare function isAppCapability(v: unknown): v is AppCapability;
|
|
724
716
|
/** What a loaded model instance can do; absent capabilities answer `unsupported-for-format`. */
|
|
725
717
|
export type InstanceCapability = 'motions' | 'expressions' | 'placement-2d' | 'placement-3d' | 'mtoon' | 'idle-clips' | 'pose' | 'live2d-params'
|
|
718
|
+
/** `instance.setBreath`; the idle breathing loop is Cubism's, so VRM lacks it. */
|
|
719
|
+
| 'breath'
|
|
726
720
|
/** `expression.setWeight`; Cubism expressions carry no user-settable weight, so Live2D lacks it. */
|
|
727
721
|
| 'expression-weights'
|
|
728
722
|
/** `speech.play` lip-sync; engine-dependent, so gate on the runtime, not the format. */
|
|
@@ -742,6 +736,8 @@ export interface InstanceRuntime {
|
|
|
742
736
|
capabilities: InstanceCapability[];
|
|
743
737
|
}
|
|
744
738
|
export interface MotionGroup {
|
|
739
|
+
/** Whether this group loops; absent on older hosts. */
|
|
740
|
+
looping?: boolean;
|
|
745
741
|
group: string;
|
|
746
742
|
files: string[];
|
|
747
743
|
}
|
|
@@ -766,20 +762,7 @@ export interface AnchorOption {
|
|
|
766
762
|
anchor: AttachAnchor;
|
|
767
763
|
label: string;
|
|
768
764
|
}
|
|
769
|
-
|
|
770
|
-
* Panel-style model info block. Format-specific fields mirror the app's `ModelInfo`.
|
|
771
|
-
* `format` stays the union's discriminant here — this is a runtime diagnostic, not
|
|
772
|
-
* content metadata, so it does not follow {@link ContentRef}'s `kind`.
|
|
773
|
-
*/
|
|
774
|
-
export interface ModelInfo {
|
|
775
|
-
format: ModelFormat;
|
|
776
|
-
name: string;
|
|
777
|
-
origin: ContentOrigin;
|
|
778
|
-
file: string;
|
|
779
|
-
loadMs: number;
|
|
780
|
-
/** Format-specific details (canvas/params/textures for Live2D, spec/bones for VRM). */
|
|
781
|
-
[key: string]: unknown;
|
|
782
|
-
}
|
|
765
|
+
export type { ModelInfo } from '../values/model-info.ts';
|
|
783
766
|
export interface Hotkey {
|
|
784
767
|
id: string;
|
|
785
768
|
name: string;
|
|
@@ -826,17 +809,17 @@ export interface ExpressionPersistence {
|
|
|
826
809
|
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
827
810
|
[key: string]: JsonValue;
|
|
828
811
|
};
|
|
829
|
-
export declare const TRACKING_SOURCE_IDS: readonly ["
|
|
812
|
+
export declare const TRACKING_SOURCE_IDS: readonly ["persona-ios", "ifacialmocap", "vts-ios"];
|
|
830
813
|
export type TrackingSourceId = (typeof TRACKING_SOURCE_IDS)[number];
|
|
831
814
|
/** Body-pose protocols. Every one so far is UDP with a configurable port. */
|
|
832
|
-
export declare const POSE_SOURCE_IDS: readonly ["vmc"];
|
|
815
|
+
export declare const POSE_SOURCE_IDS: readonly ["vmc", "mocopi"];
|
|
833
816
|
export type PoseSourceId = (typeof POSE_SOURCE_IDS)[number];
|
|
834
817
|
export type TrackingStatus = 'off' | 'waiting' | 'tracking' | 'no-face';
|
|
835
818
|
export type PoseStatus = 'off' | 'waiting' | 'tracking';
|
|
836
|
-
/** Every protocol a tracking source instance can speak; face
|
|
837
|
-
export declare const TRACKING_SOURCE_KINDS: readonly ["
|
|
819
|
+
/** Every protocol a tracking source instance can speak; face and body kinds. */
|
|
820
|
+
export declare const TRACKING_SOURCE_KINDS: readonly ["persona-ios", "ifacialmocap", "vts-ios", "vmc", "mocopi"];
|
|
838
821
|
export type TrackingSourceKind = (typeof TRACKING_SOURCE_KINDS)[number];
|
|
839
|
-
/** Whether a source kind feeds the face channel
|
|
822
|
+
/** Whether a source kind feeds the face channel. */
|
|
840
823
|
export declare function isFaceSourceKind(kind: TrackingSourceKind): kind is TrackingSourceId;
|
|
841
824
|
/**
|
|
842
825
|
* One configured tracking source instance. Several can run at once — one per person —
|
|
@@ -850,12 +833,24 @@ export interface TrackingSourceConfig {
|
|
|
850
833
|
enabled: boolean;
|
|
851
834
|
/**
|
|
852
835
|
* Face kinds: accept only this device/sender IP; null accepts any sender not claimed
|
|
853
|
-
* by a pinned instance of the same kind. Ignored by
|
|
836
|
+
* by a pinned instance of the same kind. Ignored by body sources (their senders pick the port).
|
|
854
837
|
*/
|
|
855
838
|
phoneIp: string | null;
|
|
856
|
-
/**
|
|
839
|
+
/**
|
|
840
|
+
* The UDP port this instance listens on: vmc, mocopi, and ifacialmocap (its receive port — the phone's
|
|
841
|
+
* Send Port must match). Null on persona-ios and vts-ios, whose ports the protocol fixes.
|
|
842
|
+
*/
|
|
857
843
|
port: number | null;
|
|
858
844
|
}
|
|
845
|
+
/** Whether a source feeds the body channel — the narrowing counterpart of `isFaceSourceKind`. */
|
|
846
|
+
export declare function isPoseSource(source: TrackingSourceConfig): source is TrackingSourceConfig & {
|
|
847
|
+
kind: PoseSourceId;
|
|
848
|
+
};
|
|
849
|
+
/**
|
|
850
|
+
* Whether another source already holds `port` and would contend for it. iFacialMocap instances
|
|
851
|
+
* share one socket per port (frames demux by phone); every other pairing EADDRINUSEs a listener.
|
|
852
|
+
*/
|
|
853
|
+
export declare function trackingPortTaken(sources: readonly TrackingSourceConfig[], kind: TrackingSourceKind, port: number, excludeId?: string): boolean;
|
|
859
854
|
export declare const EFFECTS_QUALITY_LEVELS: readonly ["low", "medium", "high"];
|
|
860
855
|
export type EffectsQuality = (typeof EFFECTS_QUALITY_LEVELS)[number];
|
|
861
856
|
/**
|
|
@@ -863,11 +858,20 @@ export type EffectsQuality = (typeof EFFECTS_QUALITY_LEVELS)[number];
|
|
|
863
858
|
* to the nearest preset by the app, so a picker offering other values would lie.
|
|
864
859
|
*/
|
|
865
860
|
export declare const FPS_LIMIT_PRESETS: readonly [0, 15, 30, 60, 90];
|
|
861
|
+
/** A stage window content size in device-independent px — what the desktop's window bounds report. */
|
|
862
|
+
export interface StageSize {
|
|
863
|
+
width: number;
|
|
864
|
+
height: number;
|
|
865
|
+
}
|
|
866
866
|
/** The curated settings surface the API exposes — never the raw store shape. */
|
|
867
867
|
export interface Settings {
|
|
868
|
+
/** Absent on hosts without remote controller management. */
|
|
869
|
+
controller?: ControllerConfig;
|
|
868
870
|
/** `alwaysOnTop` floats the control-panel window, never the stage. */
|
|
869
871
|
window: {
|
|
870
872
|
alwaysOnTop: boolean;
|
|
873
|
+
/** Read-only; absent on older desktops. */
|
|
874
|
+
stageSize?: StageSize;
|
|
871
875
|
};
|
|
872
876
|
ui: {
|
|
873
877
|
trayVisible: boolean;
|
|
@@ -877,6 +881,9 @@ export interface Settings {
|
|
|
877
881
|
fpsLimit: number;
|
|
878
882
|
selectionOutline: boolean;
|
|
879
883
|
effectsQuality: EffectsQuality;
|
|
884
|
+
/** Absent on older hosts. */
|
|
885
|
+
renderScale?: number;
|
|
886
|
+
live2dEngine?: 'pixi' | 'three';
|
|
880
887
|
};
|
|
881
888
|
/** `source` mirrors the first face source's kind — the pre-multi-source field, kept for old clients. */
|
|
882
889
|
tracking: {
|
|
@@ -884,7 +891,7 @@ export interface Settings {
|
|
|
884
891
|
source: TrackingSourceId;
|
|
885
892
|
sources: TrackingSourceConfig[];
|
|
886
893
|
};
|
|
887
|
-
/** `source`/`port` mirror the first
|
|
894
|
+
/** `source`/`port` mirror the first body source — the pre-multi-source fields, kept for old clients. */
|
|
888
895
|
pose: {
|
|
889
896
|
enabled: boolean;
|
|
890
897
|
source: PoseSourceId;
|
|
@@ -892,6 +899,7 @@ export interface Settings {
|
|
|
892
899
|
};
|
|
893
900
|
}
|
|
894
901
|
export interface SettingsPatch {
|
|
902
|
+
controller?: Partial<Pick<ControllerConfig, 'enabled'>>;
|
|
895
903
|
window?: {
|
|
896
904
|
alwaysOnTop?: boolean;
|
|
897
905
|
};
|
|
@@ -903,17 +911,19 @@ export interface SettingsPatch {
|
|
|
903
911
|
fpsLimit?: number;
|
|
904
912
|
selectionOutline?: boolean;
|
|
905
913
|
effectsQuality?: EffectsQuality;
|
|
914
|
+
renderScale?: number;
|
|
915
|
+
live2dEngine?: 'pixi' | 'three';
|
|
906
916
|
};
|
|
907
917
|
}
|
|
908
918
|
/** VTS's input vocabulary, plus `JawOpen` — the derived half of {@link INPUT_NAMES}. */
|
|
909
919
|
declare const VTS_INPUT_NAMES: readonly ["FaceAngleX", "FaceAngleY", "FaceAngleZ", "FacePositionX", "FacePositionY", "FacePositionZ", "EyeOpenLeft", "EyeOpenRight", "EyeLeftX", "EyeLeftY", "EyeRightX", "EyeRightY", "Brows", "BrowLeftY", "BrowRightY", "MouthSmile", "MouthOpen", "MouthX", "CheekPuff", "JawOpen", "TongueOut"];
|
|
910
920
|
type VtsInputName = (typeof VTS_INPUT_NAMES)[number];
|
|
911
921
|
/**
|
|
912
|
-
*
|
|
913
|
-
*
|
|
922
|
+
* Default input vocabulary: VTS face inputs, raw ARKit channels and controller profile 1.
|
|
923
|
+
* Additional controller profile ids are accepted by isInputName without appearing in this list.
|
|
914
924
|
*/
|
|
915
|
-
export declare const INPUT_NAMES: readonly
|
|
916
|
-
export type InputName = VtsInputName | ArkitInputName;
|
|
925
|
+
export declare const INPUT_NAMES: readonly (VtsInputName | ArkitInputName | BaseControllerInputName)[];
|
|
926
|
+
export type InputName = VtsInputName | ArkitInputName | ControllerInputName;
|
|
917
927
|
/** Whether an untrusted string names a tracking input — the guard every wire boundary needs. */
|
|
918
928
|
export declare function isInputName(v: string): v is InputName;
|
|
919
929
|
/**
|
|
@@ -938,10 +948,12 @@ export declare const BINDING_INPUT_NAMES: readonly BindingInput[];
|
|
|
938
948
|
/** The id an input is read as: its ARKit twin when it has one, else itself. */
|
|
939
949
|
export declare function arkitTwinOf(input: InputName): BindingInput;
|
|
940
950
|
/**
|
|
941
|
-
*
|
|
942
|
-
*
|
|
951
|
+
* Default inputs' natural spans. Use getInputRange for a dynamically numbered controller input.
|
|
952
|
+
* Head angles are degrees; the rest are unitless.
|
|
943
953
|
*/
|
|
944
|
-
export declare const INPUT_RANGES: Record<
|
|
954
|
+
export declare const INPUT_RANGES: Record<VtsInputName | ArkitInputName | BaseControllerInputName, readonly [number, number]>;
|
|
955
|
+
/** Natural span of any valid input, including dynamically numbered controller profiles. */
|
|
956
|
+
export declare function getInputRange(name: InputName): readonly [number, number];
|
|
945
957
|
/**
|
|
946
958
|
* What an injected value drives:
|
|
947
959
|
* - `input` — a VTS-vocabulary tracking input (`MouthOpen`, `FaceAngleX`, …), mapped
|
|
@@ -962,4 +974,3 @@ export interface InjectEntry extends InjectTarget {
|
|
|
962
974
|
/** 0..1 blend over whatever else drives the parameter; default 1. */
|
|
963
975
|
weight?: number;
|
|
964
976
|
}
|
|
965
|
-
export {};
|
package/dist/wire/types.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
// carry. Structural mirrors of the app's scene/settings models, minus anything
|
|
3
3
|
// filesystem-shaped — model refs are sanitized to ids, never directories.
|
|
4
4
|
import { ARKIT_INPUT_NAMES } from "../values/arkit.js";
|
|
5
|
+
import { BASE_CONTROLLER_INPUT_NAMES, BASE_CONTROLLER_INPUT_RANGES, controllerInputRange, isControllerInputName, } from "../values/controller.js";
|
|
5
6
|
/**
|
|
6
7
|
* How a registered file is labelled. Wider than an object's content kinds: `.hdr` is only
|
|
7
8
|
* ever an environment map, and a `.vmd` splits by content — `cameraMotion` for one that
|
|
@@ -23,7 +24,14 @@ export const SHADOW_QUALITY_LEVELS = ['off', 'low', 'medium', 'high', 'ultra'];
|
|
|
23
24
|
* App-level features a client gates on (never version-sniff): `hello` and
|
|
24
25
|
* `app.info` report them — the per-app mirror of {@link InstanceRuntime.capabilities}.
|
|
25
26
|
*/
|
|
26
|
-
export const APP_CAPABILITIES = [
|
|
27
|
+
export const APP_CAPABILITIES = [
|
|
28
|
+
'storage',
|
|
29
|
+
'speech',
|
|
30
|
+
'shortcuts',
|
|
31
|
+
'controllers',
|
|
32
|
+
'model-editing',
|
|
33
|
+
'asset-inspection',
|
|
34
|
+
];
|
|
27
35
|
export function isAppCapability(v) {
|
|
28
36
|
return typeof v === 'string' && APP_CAPABILITIES.includes(v);
|
|
29
37
|
}
|
|
@@ -38,15 +46,26 @@ export const SHORTCUT_ACTION_KINDS = [
|
|
|
38
46
|
'stream-mode',
|
|
39
47
|
];
|
|
40
48
|
// ---- Settings ------------------------------------------------------------------
|
|
41
|
-
export const TRACKING_SOURCE_IDS = ['
|
|
49
|
+
export const TRACKING_SOURCE_IDS = ['persona-ios', 'ifacialmocap', 'vts-ios'];
|
|
42
50
|
/** Body-pose protocols. Every one so far is UDP with a configurable port. */
|
|
43
|
-
export const POSE_SOURCE_IDS = ['vmc'];
|
|
44
|
-
/** Every protocol a tracking source instance can speak; face
|
|
51
|
+
export const POSE_SOURCE_IDS = ['vmc', 'mocopi'];
|
|
52
|
+
/** Every protocol a tracking source instance can speak; face and body kinds. */
|
|
45
53
|
export const TRACKING_SOURCE_KINDS = [...TRACKING_SOURCE_IDS, ...POSE_SOURCE_IDS];
|
|
46
|
-
/** Whether a source kind feeds the face channel
|
|
54
|
+
/** Whether a source kind feeds the face channel. */
|
|
47
55
|
export function isFaceSourceKind(kind) {
|
|
48
56
|
return TRACKING_SOURCE_IDS.includes(kind);
|
|
49
57
|
}
|
|
58
|
+
/** Whether a source feeds the body channel — the narrowing counterpart of `isFaceSourceKind`. */
|
|
59
|
+
export function isPoseSource(source) {
|
|
60
|
+
return !isFaceSourceKind(source.kind);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Whether another source already holds `port` and would contend for it. iFacialMocap instances
|
|
64
|
+
* share one socket per port (frames demux by phone); every other pairing EADDRINUSEs a listener.
|
|
65
|
+
*/
|
|
66
|
+
export function trackingPortTaken(sources, kind, port, excludeId) {
|
|
67
|
+
return sources.some(s => s.id !== excludeId && s.port === port && !(s.kind === 'ifacialmocap' && kind === 'ifacialmocap'));
|
|
68
|
+
}
|
|
50
69
|
export const EFFECTS_QUALITY_LEVELS = ['low', 'medium', 'high'];
|
|
51
70
|
/**
|
|
52
71
|
* Accepted values for `performance.fpsLimit`; 0 = unlimited. Anything else is snapped
|
|
@@ -79,14 +98,18 @@ const VTS_INPUT_NAMES = [
|
|
|
79
98
|
'TongueOut',
|
|
80
99
|
];
|
|
81
100
|
/**
|
|
82
|
-
*
|
|
83
|
-
*
|
|
101
|
+
* Default input vocabulary: VTS face inputs, raw ARKit channels and controller profile 1.
|
|
102
|
+
* Additional controller profile ids are accepted by isInputName without appearing in this list.
|
|
84
103
|
*/
|
|
85
|
-
export const INPUT_NAMES = [
|
|
104
|
+
export const INPUT_NAMES = [
|
|
105
|
+
...VTS_INPUT_NAMES,
|
|
106
|
+
...ARKIT_INPUT_NAMES,
|
|
107
|
+
...BASE_CONTROLLER_INPUT_NAMES,
|
|
108
|
+
];
|
|
86
109
|
const INPUT_NAME_SET = new Set(INPUT_NAMES);
|
|
87
110
|
/** Whether an untrusted string names a tracking input — the guard every wire boundary needs. */
|
|
88
111
|
export function isInputName(v) {
|
|
89
|
-
return INPUT_NAME_SET.has(v);
|
|
112
|
+
return INPUT_NAME_SET.has(v) || isControllerInputName(v);
|
|
90
113
|
}
|
|
91
114
|
/**
|
|
92
115
|
* VTS-vocabulary inputs that are the same float as one raw ARKit channel (the desktop derives
|
|
@@ -145,12 +168,17 @@ const VTS_INPUT_RANGES = {
|
|
|
145
168
|
/** ARKit blendshapes are unit-scale by definition, so every raw channel shares one span. */
|
|
146
169
|
const ARKIT_RANGE = [0, 1];
|
|
147
170
|
/**
|
|
148
|
-
*
|
|
149
|
-
*
|
|
171
|
+
* Default inputs' natural spans. Use getInputRange for a dynamically numbered controller input.
|
|
172
|
+
* Head angles are degrees; the rest are unitless.
|
|
150
173
|
*/
|
|
151
174
|
export const INPUT_RANGES = {
|
|
152
175
|
...VTS_INPUT_RANGES,
|
|
176
|
+
...BASE_CONTROLLER_INPUT_RANGES,
|
|
153
177
|
// `fromEntries` widens the key type back to `string`; the annotation above is what keeps
|
|
154
178
|
// this exhaustive, and it fails to typecheck if a name ever lacks a range.
|
|
155
179
|
...Object.fromEntries(ARKIT_INPUT_NAMES.map(n => [n, ARKIT_RANGE])),
|
|
156
180
|
};
|
|
181
|
+
/** Natural span of any valid input, including dynamically numbered controller profiles. */
|
|
182
|
+
export function getInputRange(name) {
|
|
183
|
+
return isControllerInputName(name) ? controllerInputRange(name) : INPUT_RANGES[name];
|
|
184
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@laplace.live/persona-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "TypeScript SDK and wire schema for the LAPLACE Persona plugin API",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -16,10 +16,6 @@
|
|
|
16
16
|
".": {
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
18
|
"import": "./dist/index.js"
|
|
19
|
-
},
|
|
20
|
-
"./effects": {
|
|
21
|
-
"types": "./dist/effects.d.ts",
|
|
22
|
-
"import": "./dist/effects.js"
|
|
23
19
|
}
|
|
24
20
|
},
|
|
25
21
|
"files": [
|
|
@@ -30,22 +26,12 @@
|
|
|
30
26
|
"provenance": true
|
|
31
27
|
},
|
|
32
28
|
"devDependencies": {
|
|
33
|
-
"@types/three": "^0.185.4",
|
|
34
29
|
"rimraf": "^6.1.3",
|
|
35
|
-
"three": "0.185.1",
|
|
36
30
|
"typescript": "~6.0.3",
|
|
37
31
|
"vitest": "^4.1.11"
|
|
38
32
|
},
|
|
39
|
-
"peerDependencies": {
|
|
40
|
-
"@types/three": "^0.185.0"
|
|
41
|
-
},
|
|
42
|
-
"peerDependenciesMeta": {
|
|
43
|
-
"@types/three": {
|
|
44
|
-
"optional": true
|
|
45
|
-
}
|
|
46
|
-
},
|
|
47
33
|
"engines": {
|
|
48
|
-
"node": ">=
|
|
34
|
+
"node": ">=24"
|
|
49
35
|
},
|
|
50
36
|
"dependencies": {
|
|
51
37
|
"zod": "^4.5.4"
|
package/dist/effects.d.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import type * as TSL from 'three/tsl';
|
|
2
|
-
import type { Color, Node, Vector2, Vector3, Vector4 } from 'three/webgpu';
|
|
3
|
-
export * from './values/custom-effect.ts';
|
|
4
|
-
/** A vec4-typed TSL node with its swizzles — what `sample` returns and `build` composes over. */
|
|
5
|
-
export type CustomEffectVec4 = ReturnType<typeof TSL.nodeObject<Node<'vec4'>>>;
|
|
6
|
-
/** A float-typed TSL node with its operators — what `viewZ` returns. */
|
|
7
|
-
export type CustomEffectFloat = ReturnType<typeof TSL.nodeObject<Node<'float'>>>;
|
|
8
|
-
/** A vec3-typed TSL node with its swizzles — what the camera probes return. */
|
|
9
|
-
export type CustomEffectVec3 = ReturnType<typeof TSL.nodeObject<Node<'vec3'>>>;
|
|
10
|
-
/** What an author's module receives. Not a security boundary — just the useful surface. */
|
|
11
|
-
export interface CustomEffectApi {
|
|
12
|
-
/** The whole `three/tsl` namespace: `vec4`, `uv`, `uniform`, `mix`, `Fn`, … */
|
|
13
|
-
tsl: typeof TSL;
|
|
14
|
-
three: {
|
|
15
|
-
Color: typeof Color;
|
|
16
|
-
Vector2: typeof Vector2;
|
|
17
|
-
Vector3: typeof Vector3;
|
|
18
|
-
Vector4: typeof Vector4;
|
|
19
|
-
};
|
|
20
|
-
/**
|
|
21
|
-
* Stock three display nodes an effect cannot build for itself. `afterImage`
|
|
22
|
-
* is the seam for anything temporal: correct frame feedback needs two render
|
|
23
|
-
* targets ping-ponged plus a renderer reference, and `build()` hands authors
|
|
24
|
-
* neither. Upstream types return the bare class, hiding the TSL swizzles the
|
|
25
|
-
* runtime proxy carries; this signature types the echo as what authors use it
|
|
26
|
-
* as — a sampleable vec4 image.
|
|
27
|
-
*/
|
|
28
|
-
nodes: {
|
|
29
|
-
afterImage: (node: Node, damp?: Node | number) => CustomEffectVec4;
|
|
30
|
-
};
|
|
31
|
-
}
|
|
32
|
-
/** Build-time context for one custom effect. */
|
|
33
|
-
export interface CustomEffectBuildContext {
|
|
34
|
-
/** Sample the incoming frame at any UV — the seam that makes warps and blurs possible. */
|
|
35
|
-
sample: (at: unknown) => CustomEffectVec4;
|
|
36
|
-
/** Screen UV of the pixel being shaded. */
|
|
37
|
-
uv: typeof TSL.uv;
|
|
38
|
-
/**
|
|
39
|
-
* View-space Z of the 3D scene at this pixel — three's convention: 0 at the
|
|
40
|
-
* camera, more negative with distance, the far plane where nothing was drawn.
|
|
41
|
-
* The Live2D layer and 2D objects contribute no depth. Costs one depth read,
|
|
42
|
-
* and only if called.
|
|
43
|
-
*/
|
|
44
|
-
viewZ: () => CustomEffectFloat;
|
|
45
|
-
/**
|
|
46
|
-
* Normalized world-space direction of the scene camera's view ray through
|
|
47
|
-
* this pixel, fov and aspect folded in. Inside the post pass TSL's own
|
|
48
|
-
* `cameraPosition`/`cameraWorldMatrix` describe the fullscreen quad's
|
|
49
|
-
* camera — this is the real one. Anchor a field here instead of `uv()` and
|
|
50
|
-
* it holds still in the world while the camera orbits.
|
|
51
|
-
*/
|
|
52
|
-
worldRay: () => CustomEffectVec3;
|
|
53
|
-
/** The scene camera's world position in metres, as a per-frame uniform. */
|
|
54
|
-
cameraPosition: () => CustomEffectVec3;
|
|
55
|
-
/** Hand a build-time disposable (a blur render target) to the chain's transient list. */
|
|
56
|
-
track: (t: {
|
|
57
|
-
dispose?: () => void;
|
|
58
|
-
}) => void;
|
|
59
|
-
}
|
|
60
|
-
/** What an author's module returns. Everything but `build` is optional. */
|
|
61
|
-
export interface CustomEffectModule {
|
|
62
|
-
/** Uniform nodes keyed by manifest param name; param edits write straight into `.value`. */
|
|
63
|
-
uniforms?: Record<string, {
|
|
64
|
-
value: unknown;
|
|
65
|
-
}>;
|
|
66
|
-
/** Compose the effect over `input` — the frame so far, already sampleable — and return the result node. */
|
|
67
|
-
build: (input: Node, ctx: CustomEffectBuildContext) => Node;
|
|
68
|
-
/** Per-frame CPU state. `dt` and `elapsed` are seconds. */
|
|
69
|
-
update?: (dt: number, elapsed: number) => void;
|
|
70
|
-
dispose?: () => void;
|
|
71
|
-
}
|
|
72
|
-
/** The module's default export. Runs once per load — mint uniforms here so they survive rebuilds. */
|
|
73
|
-
export type CustomEffectFactory = (api: CustomEffectApi) => CustomEffectModule;
|
|
74
|
-
/** Why an effect is not rendering, for the panel's error row. */
|
|
75
|
-
export interface CustomEffectFault {
|
|
76
|
-
slug: string;
|
|
77
|
-
phase: 'load' | 'build' | 'update';
|
|
78
|
-
message: string;
|
|
79
|
-
}
|