@laplace.live/persona-sdk 0.18.1 → 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 +5 -8
- package/dist/values/curve.js +16 -7
- 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 +19 -0
- package/dist/values/limits.js +27 -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 +59 -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;
|
|
@@ -188,6 +194,8 @@ export type ObjectContent = {
|
|
|
188
194
|
css: string;
|
|
189
195
|
/** 2D only: composited behind or in front of the whole stage, not interleaved with other layers. */
|
|
190
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;
|
|
191
199
|
} | {
|
|
192
200
|
kind: 'capture';
|
|
193
201
|
source: CaptureKind;
|
|
@@ -602,24 +610,6 @@ export type ToggleEffectKey = {
|
|
|
602
610
|
enabled: boolean;
|
|
603
611
|
} ? K : never;
|
|
604
612
|
}[keyof SceneEffects];
|
|
605
|
-
/**
|
|
606
|
-
* One user-authored effect's placement in a scene. Deliberately a sibling of
|
|
607
|
-
* {@link SceneEffects} rather than a key inside it: `ToggleEffectKey` is derived
|
|
608
|
-
* from that interface, and healing, defaults, hotkey snapshots and the panel all
|
|
609
|
-
* iterate it as a closed compile-time union. Runtime keys in there would erase
|
|
610
|
-
* that guarantee for the built-in effects too.
|
|
611
|
-
*/
|
|
612
|
-
export interface SceneCustomEffect {
|
|
613
|
-
/** Folder name under the config home's `effects/` dir — stable id and module location. */
|
|
614
|
-
slug: string;
|
|
615
|
-
enabled: boolean;
|
|
616
|
-
/**
|
|
617
|
-
* Author-declared values, keyed by the manifest's param names. Untyped by
|
|
618
|
-
* construction: the specs arrive from disk at runtime, so these are validated
|
|
619
|
-
* against the installed manifest rather than checked at compile time.
|
|
620
|
-
*/
|
|
621
|
-
params: Record<string, number | boolean | string>;
|
|
622
|
-
}
|
|
623
613
|
/**
|
|
624
614
|
* A 3D set's own suggested look — the fog and post settings it was authored against,
|
|
625
615
|
* read from its root `LAPLACE_environment` extension and held on the scene for every client.
|
|
@@ -681,14 +671,6 @@ export interface SceneEnvironment {
|
|
|
681
671
|
* switched off. Healing lists every switched-on effect, so a patch that switches one on adds its layer.
|
|
682
672
|
*/
|
|
683
673
|
effectLayers: ToggleEffectKey[];
|
|
684
|
-
/**
|
|
685
|
-
* User-authored effects, in the order they compose. They run as a group at one
|
|
686
|
-
* fixed point in the post chain — after grading and the screen-space warps,
|
|
687
|
-
* before grain and vignette — so the built-in composition order stays fixed.
|
|
688
|
-
* An entry whose effect is not installed here is kept, not dropped: it would
|
|
689
|
-
* cost the user their tuning on a machine that simply lacks the folder.
|
|
690
|
-
*/
|
|
691
|
-
customEffects: SceneCustomEffect[];
|
|
692
674
|
}
|
|
693
675
|
export interface Scene {
|
|
694
676
|
id: string;
|
|
@@ -728,11 +710,13 @@ export interface ScenePatch {
|
|
|
728
710
|
* App-level features a client gates on (never version-sniff): `hello` and
|
|
729
711
|
* `app.info` report them — the per-app mirror of {@link InstanceRuntime.capabilities}.
|
|
730
712
|
*/
|
|
731
|
-
export declare const APP_CAPABILITIES: readonly ["storage", "speech", "shortcuts"];
|
|
713
|
+
export declare const APP_CAPABILITIES: readonly ["storage", "speech", "shortcuts", "controllers", "model-editing", "asset-inspection"];
|
|
732
714
|
export type AppCapability = (typeof APP_CAPABILITIES)[number];
|
|
733
715
|
export declare function isAppCapability(v: unknown): v is AppCapability;
|
|
734
716
|
/** What a loaded model instance can do; absent capabilities answer `unsupported-for-format`. */
|
|
735
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'
|
|
736
720
|
/** `expression.setWeight`; Cubism expressions carry no user-settable weight, so Live2D lacks it. */
|
|
737
721
|
| 'expression-weights'
|
|
738
722
|
/** `speech.play` lip-sync; engine-dependent, so gate on the runtime, not the format. */
|
|
@@ -752,6 +736,8 @@ export interface InstanceRuntime {
|
|
|
752
736
|
capabilities: InstanceCapability[];
|
|
753
737
|
}
|
|
754
738
|
export interface MotionGroup {
|
|
739
|
+
/** Whether this group loops; absent on older hosts. */
|
|
740
|
+
looping?: boolean;
|
|
755
741
|
group: string;
|
|
756
742
|
files: string[];
|
|
757
743
|
}
|
|
@@ -776,20 +762,7 @@ export interface AnchorOption {
|
|
|
776
762
|
anchor: AttachAnchor;
|
|
777
763
|
label: string;
|
|
778
764
|
}
|
|
779
|
-
|
|
780
|
-
* Panel-style model info block. Format-specific fields mirror the app's `ModelInfo`.
|
|
781
|
-
* `format` stays the union's discriminant here — this is a runtime diagnostic, not
|
|
782
|
-
* content metadata, so it does not follow {@link ContentRef}'s `kind`.
|
|
783
|
-
*/
|
|
784
|
-
export interface ModelInfo {
|
|
785
|
-
format: ModelFormat;
|
|
786
|
-
name: string;
|
|
787
|
-
origin: ContentOrigin;
|
|
788
|
-
file: string;
|
|
789
|
-
loadMs: number;
|
|
790
|
-
/** Format-specific details (canvas/params/textures for Live2D, spec/bones for VRM). */
|
|
791
|
-
[key: string]: unknown;
|
|
792
|
-
}
|
|
765
|
+
export type { ModelInfo } from '../values/model-info.ts';
|
|
793
766
|
export interface Hotkey {
|
|
794
767
|
id: string;
|
|
795
768
|
name: string;
|
|
@@ -836,17 +809,17 @@ export interface ExpressionPersistence {
|
|
|
836
809
|
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
837
810
|
[key: string]: JsonValue;
|
|
838
811
|
};
|
|
839
|
-
export declare const TRACKING_SOURCE_IDS: readonly ["
|
|
812
|
+
export declare const TRACKING_SOURCE_IDS: readonly ["persona-ios", "ifacialmocap", "vts-ios"];
|
|
840
813
|
export type TrackingSourceId = (typeof TRACKING_SOURCE_IDS)[number];
|
|
841
814
|
/** Body-pose protocols. Every one so far is UDP with a configurable port. */
|
|
842
|
-
export declare const POSE_SOURCE_IDS: readonly ["vmc"];
|
|
815
|
+
export declare const POSE_SOURCE_IDS: readonly ["vmc", "mocopi"];
|
|
843
816
|
export type PoseSourceId = (typeof POSE_SOURCE_IDS)[number];
|
|
844
817
|
export type TrackingStatus = 'off' | 'waiting' | 'tracking' | 'no-face';
|
|
845
818
|
export type PoseStatus = 'off' | 'waiting' | 'tracking';
|
|
846
|
-
/** Every protocol a tracking source instance can speak; face
|
|
847
|
-
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"];
|
|
848
821
|
export type TrackingSourceKind = (typeof TRACKING_SOURCE_KINDS)[number];
|
|
849
|
-
/** Whether a source kind feeds the face channel
|
|
822
|
+
/** Whether a source kind feeds the face channel. */
|
|
850
823
|
export declare function isFaceSourceKind(kind: TrackingSourceKind): kind is TrackingSourceId;
|
|
851
824
|
/**
|
|
852
825
|
* One configured tracking source instance. Several can run at once — one per person —
|
|
@@ -860,12 +833,24 @@ export interface TrackingSourceConfig {
|
|
|
860
833
|
enabled: boolean;
|
|
861
834
|
/**
|
|
862
835
|
* Face kinds: accept only this device/sender IP; null accepts any sender not claimed
|
|
863
|
-
* 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).
|
|
864
837
|
*/
|
|
865
838
|
phoneIp: string | null;
|
|
866
|
-
/**
|
|
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
|
+
*/
|
|
867
843
|
port: number | null;
|
|
868
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;
|
|
869
854
|
export declare const EFFECTS_QUALITY_LEVELS: readonly ["low", "medium", "high"];
|
|
870
855
|
export type EffectsQuality = (typeof EFFECTS_QUALITY_LEVELS)[number];
|
|
871
856
|
/**
|
|
@@ -873,11 +858,20 @@ export type EffectsQuality = (typeof EFFECTS_QUALITY_LEVELS)[number];
|
|
|
873
858
|
* to the nearest preset by the app, so a picker offering other values would lie.
|
|
874
859
|
*/
|
|
875
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
|
+
}
|
|
876
866
|
/** The curated settings surface the API exposes — never the raw store shape. */
|
|
877
867
|
export interface Settings {
|
|
868
|
+
/** Absent on hosts without remote controller management. */
|
|
869
|
+
controller?: ControllerConfig;
|
|
878
870
|
/** `alwaysOnTop` floats the control-panel window, never the stage. */
|
|
879
871
|
window: {
|
|
880
872
|
alwaysOnTop: boolean;
|
|
873
|
+
/** Read-only; absent on older desktops. */
|
|
874
|
+
stageSize?: StageSize;
|
|
881
875
|
};
|
|
882
876
|
ui: {
|
|
883
877
|
trayVisible: boolean;
|
|
@@ -887,6 +881,9 @@ export interface Settings {
|
|
|
887
881
|
fpsLimit: number;
|
|
888
882
|
selectionOutline: boolean;
|
|
889
883
|
effectsQuality: EffectsQuality;
|
|
884
|
+
/** Absent on older hosts. */
|
|
885
|
+
renderScale?: number;
|
|
886
|
+
live2dEngine?: 'pixi' | 'three';
|
|
890
887
|
};
|
|
891
888
|
/** `source` mirrors the first face source's kind — the pre-multi-source field, kept for old clients. */
|
|
892
889
|
tracking: {
|
|
@@ -894,7 +891,7 @@ export interface Settings {
|
|
|
894
891
|
source: TrackingSourceId;
|
|
895
892
|
sources: TrackingSourceConfig[];
|
|
896
893
|
};
|
|
897
|
-
/** `source`/`port` mirror the first
|
|
894
|
+
/** `source`/`port` mirror the first body source — the pre-multi-source fields, kept for old clients. */
|
|
898
895
|
pose: {
|
|
899
896
|
enabled: boolean;
|
|
900
897
|
source: PoseSourceId;
|
|
@@ -902,6 +899,7 @@ export interface Settings {
|
|
|
902
899
|
};
|
|
903
900
|
}
|
|
904
901
|
export interface SettingsPatch {
|
|
902
|
+
controller?: Partial<Pick<ControllerConfig, 'enabled'>>;
|
|
905
903
|
window?: {
|
|
906
904
|
alwaysOnTop?: boolean;
|
|
907
905
|
};
|
|
@@ -913,17 +911,19 @@ export interface SettingsPatch {
|
|
|
913
911
|
fpsLimit?: number;
|
|
914
912
|
selectionOutline?: boolean;
|
|
915
913
|
effectsQuality?: EffectsQuality;
|
|
914
|
+
renderScale?: number;
|
|
915
|
+
live2dEngine?: 'pixi' | 'three';
|
|
916
916
|
};
|
|
917
917
|
}
|
|
918
918
|
/** VTS's input vocabulary, plus `JawOpen` — the derived half of {@link INPUT_NAMES}. */
|
|
919
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"];
|
|
920
920
|
type VtsInputName = (typeof VTS_INPUT_NAMES)[number];
|
|
921
921
|
/**
|
|
922
|
-
*
|
|
923
|
-
*
|
|
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.
|
|
924
924
|
*/
|
|
925
|
-
export declare const INPUT_NAMES: readonly
|
|
926
|
-
export type InputName = VtsInputName | ArkitInputName;
|
|
925
|
+
export declare const INPUT_NAMES: readonly (VtsInputName | ArkitInputName | BaseControllerInputName)[];
|
|
926
|
+
export type InputName = VtsInputName | ArkitInputName | ControllerInputName;
|
|
927
927
|
/** Whether an untrusted string names a tracking input — the guard every wire boundary needs. */
|
|
928
928
|
export declare function isInputName(v: string): v is InputName;
|
|
929
929
|
/**
|
|
@@ -948,10 +948,12 @@ export declare const BINDING_INPUT_NAMES: readonly BindingInput[];
|
|
|
948
948
|
/** The id an input is read as: its ARKit twin when it has one, else itself. */
|
|
949
949
|
export declare function arkitTwinOf(input: InputName): BindingInput;
|
|
950
950
|
/**
|
|
951
|
-
*
|
|
952
|
-
*
|
|
951
|
+
* Default inputs' natural spans. Use getInputRange for a dynamically numbered controller input.
|
|
952
|
+
* Head angles are degrees; the rest are unitless.
|
|
953
953
|
*/
|
|
954
|
-
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];
|
|
955
957
|
/**
|
|
956
958
|
* What an injected value drives:
|
|
957
959
|
* - `input` — a VTS-vocabulary tracking input (`MouthOpen`, `FaceAngleX`, …), mapped
|
|
@@ -972,4 +974,3 @@ export interface InjectEntry extends InjectTarget {
|
|
|
972
974
|
/** 0..1 blend over whatever else drives the parameter; default 1. */
|
|
973
975
|
weight?: number;
|
|
974
976
|
}
|
|
975
|
-
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
|
-
}
|
package/dist/effects.js
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
// The custom-effect authoring contract: what an effect module receives, what it
|
|
2
|
-
// returns, and (re-exported) the manifest shape naming its params. Everything
|
|
3
|
-
// touching three is type-only — the desktop hands the runtime to the module's
|
|
4
|
-
// factory, because a module loaded from `persona://` can import nothing.
|
|
5
|
-
// Typechecking against this entry needs `@types/three` (optional peer).
|
|
6
|
-
export * from "./values/custom-effect.js";
|