@laplace.live/persona-sdk 1.0.0 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/values/effect-schema.d.ts +71 -11
- package/dist/values/effect-schema.js +278 -65
- package/dist/values/hands.d.ts +53 -0
- package/dist/values/hands.js +89 -0
- package/dist/values/lipsync.d.ts +106 -0
- package/dist/values/lipsync.js +120 -0
- package/dist/wire/events.d.ts +1 -1
- package/dist/wire/methods.d.ts +60 -1
- package/dist/wire/protocol.d.ts +1 -1
- package/dist/wire/protocol.js +1 -1
- package/dist/wire/schemas.d.ts +76 -3
- package/dist/wire/schemas.js +28 -0
- package/dist/wire/types.d.ts +245 -83
- package/dist/wire/types.js +55 -5
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -20,7 +20,9 @@ await persona.connect();
|
|
|
20
20
|
// Typed request/response
|
|
21
21
|
const { scenes, activeSceneId } = await persona.call("scene.list");
|
|
22
22
|
await persona.call("expression.toggle", { name: "Smile" });
|
|
23
|
-
await persona.call("scene.patch", {
|
|
23
|
+
await persona.call("scene.patch", {
|
|
24
|
+
background: { mode: "color", color: "#112233", imageAssetId: null },
|
|
25
|
+
});
|
|
24
26
|
|
|
25
27
|
// Events (subscriptions survive reconnects)
|
|
26
28
|
persona.on("motion.started", (m) => console.log("playing", m.group));
|
package/dist/index.d.ts
CHANGED
|
@@ -8,9 +8,11 @@ export * from './values/edit-history.ts';
|
|
|
8
8
|
export * from './values/effect-schema.ts';
|
|
9
9
|
export * from './values/gltf-extensions.ts';
|
|
10
10
|
export * from './values/guards.ts';
|
|
11
|
+
export * from './values/hands.ts';
|
|
11
12
|
export * from './values/hotkeys.ts';
|
|
12
13
|
export * from './values/labels.ts';
|
|
13
14
|
export * from './values/limits.ts';
|
|
15
|
+
export * from './values/lipsync.ts';
|
|
14
16
|
export * from './values/locale.ts';
|
|
15
17
|
export * from './values/model-info.ts';
|
|
16
18
|
export * from './values/stage-info.ts';
|
package/dist/index.js
CHANGED
|
@@ -10,9 +10,11 @@ export * from "./values/edit-history.js";
|
|
|
10
10
|
export * from "./values/effect-schema.js";
|
|
11
11
|
export * from "./values/gltf-extensions.js";
|
|
12
12
|
export * from "./values/guards.js";
|
|
13
|
+
export * from "./values/hands.js";
|
|
13
14
|
export * from "./values/hotkeys.js";
|
|
14
15
|
export * from "./values/labels.js";
|
|
15
16
|
export * from "./values/limits.js";
|
|
17
|
+
export * from "./values/lipsync.js";
|
|
16
18
|
export * from "./values/locale.js";
|
|
17
19
|
export * from "./values/model-info.js";
|
|
18
20
|
export * from "./values/stage-info.js";
|
|
@@ -1,4 +1,38 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { EffectKey, EffectKeyForScope, EffectScope, EffectValues, LayerEffectKey, LayerEffects, SceneEffectKey } from '../wire/types.ts';
|
|
2
|
+
/** Supported owners of each toggle effect; scene and layer membership are independent. */
|
|
3
|
+
export declare const EFFECT_SCOPES: {
|
|
4
|
+
readonly color: readonly ["scene", "layer"];
|
|
5
|
+
readonly levels: readonly ["scene", "layer"];
|
|
6
|
+
readonly colorWheels: readonly ["scene", "layer"];
|
|
7
|
+
readonly colorShift: readonly ["scene", "layer"];
|
|
8
|
+
readonly selectColors: readonly ["scene", "layer"];
|
|
9
|
+
readonly blur: readonly ["scene", "layer"];
|
|
10
|
+
readonly bloom: readonly ["scene", "layer"];
|
|
11
|
+
readonly diffusion: readonly ["scene", "layer"];
|
|
12
|
+
readonly dof: readonly ["scene"];
|
|
13
|
+
readonly chromaticAberration: readonly ["scene"];
|
|
14
|
+
readonly grain: readonly ["scene"];
|
|
15
|
+
readonly vignette: readonly ["scene"];
|
|
16
|
+
readonly rim: readonly ["scene", "layer"];
|
|
17
|
+
readonly outline: readonly ["scene", "layer"];
|
|
18
|
+
readonly dropShadow: readonly ["scene", "layer"];
|
|
19
|
+
readonly pixelate: readonly ["scene"];
|
|
20
|
+
readonly glitch: readonly ["scene"];
|
|
21
|
+
readonly droplets: readonly ["scene"];
|
|
22
|
+
readonly rain: readonly ["scene"];
|
|
23
|
+
readonly snow: readonly ["scene"];
|
|
24
|
+
};
|
|
25
|
+
export declare const EFFECT_KEYS: readonly EffectKey[];
|
|
26
|
+
/** Older hosts advertise effect availability through the values present in their payload. */
|
|
27
|
+
export declare function availableEffectKeys<S extends EffectScope>(scope: S, effects: Partial<Record<EffectKey, unknown>>): EffectKeyForScope<S>[];
|
|
28
|
+
/** Preserve the option shape advertised by the host when resetting or applying settings. */
|
|
29
|
+
export declare function supportedEffectParams<T extends object>(current: T, patch: Partial<T>): Partial<T>;
|
|
30
|
+
/** Named modes distinguish the newer rim/outline size and bloom intensity units from older hosts. */
|
|
31
|
+
export declare function hasCurrentEffectFormat(effect: EffectKey, value: object): boolean;
|
|
32
|
+
export declare const SCENE_EFFECT_KEYS: readonly EffectKeyForScope<"scene">[];
|
|
33
|
+
/** Scene toggle keys; retained for existing SDK consumers. */
|
|
34
|
+
export declare const TOGGLE_EFFECT_KEYS: readonly EffectKeyForScope<"scene">[];
|
|
35
|
+
export declare const LAYER_EFFECT_KEYS: readonly EffectKeyForScope<"layer">[];
|
|
2
36
|
/** Slider + healing metadata for one numeric effect parameter. */
|
|
3
37
|
export interface EffectParamSpec {
|
|
4
38
|
default: number;
|
|
@@ -14,28 +48,54 @@ export interface EffectParamSpec {
|
|
|
14
48
|
export interface EffectColorSpec {
|
|
15
49
|
default: string;
|
|
16
50
|
}
|
|
17
|
-
|
|
51
|
+
/** Boolean effect parameters other than the common enabled switch. */
|
|
52
|
+
export interface EffectBooleanSpec {
|
|
53
|
+
default: boolean;
|
|
54
|
+
}
|
|
55
|
+
/** Named choices; values are protocol strings and labels belong to the UI. */
|
|
56
|
+
export interface EffectEnumSpec<T extends string = string> {
|
|
57
|
+
default: T;
|
|
58
|
+
values: readonly T[];
|
|
59
|
+
}
|
|
60
|
+
export declare const EFFECT_SPECS: Record<EffectKey, Readonly<Record<string, EffectParamSpec>>>;
|
|
18
61
|
/**
|
|
19
62
|
* Hex-color params, keyed like {@link EFFECT_SPECS} — generic walkers (healing,
|
|
20
63
|
* defaults, hotkey snapshots, the panel) visit both tables. Only effects with a
|
|
21
64
|
* string param appear.
|
|
22
65
|
*/
|
|
23
|
-
export declare const EFFECT_COLOR_SPECS: Partial<Record<
|
|
24
|
-
|
|
66
|
+
export declare const EFFECT_COLOR_SPECS: Partial<Record<EffectKey, Readonly<Record<string, EffectColorSpec>>>>;
|
|
67
|
+
/** Boolean defaults, validated alongside numeric and color parameters. */
|
|
68
|
+
export declare const EFFECT_BOOLEAN_SPECS: Partial<Record<EffectKey, Readonly<Record<string, EffectBooleanSpec>>>>;
|
|
69
|
+
/** Enum defaults and allowed values. */
|
|
70
|
+
export declare const EFFECT_ENUM_SPECS: Partial<Record<EffectKey, Readonly<Record<string, EffectEnumSpec>>>>;
|
|
71
|
+
/** Select the layer effects from any value set containing them. */
|
|
72
|
+
export declare function pickLayerEffects<T extends LayerEffects>(effects: T): LayerEffects;
|
|
73
|
+
/** The canonical per-item effect list, preserving disabled rows and including every enabled effect. */
|
|
74
|
+
export declare function layerEffectKeys(listed: readonly unknown[], effects: LayerEffects): LayerEffectKey[];
|
|
75
|
+
/** An independent, disabled set for a fresh source layer. */
|
|
76
|
+
export declare function defaultLayerEffects(): LayerEffects;
|
|
77
|
+
/** Whether a source needs its own effect pass. */
|
|
78
|
+
export declare function layerEffectsActive(effects: LayerEffects): boolean;
|
|
25
79
|
/**
|
|
26
80
|
* Registry effects that render as scene geometry inside the scene pass rather
|
|
27
81
|
* than composing into the post chain. A new scene-space effect must join this
|
|
28
82
|
* list, or its toggle needlessly forces the post path on and rebuilds the graph.
|
|
29
83
|
*/
|
|
30
|
-
export declare const SCENE_SPACE_EFFECT_KEYS: readonly
|
|
84
|
+
export declare const SCENE_SPACE_EFFECT_KEYS: readonly SceneEffectKey[];
|
|
31
85
|
/** Registry effects the post chain composes — {@link TOGGLE_EFFECT_KEYS} minus the scene-space ones. */
|
|
32
|
-
export declare const POST_EFFECT_KEYS: readonly
|
|
33
|
-
/** The canonical `effectLayers
|
|
34
|
-
export declare function effectLayerKeys(listed: readonly unknown[], effects: Pick<
|
|
86
|
+
export declare const POST_EFFECT_KEYS: readonly SceneEffectKey[];
|
|
87
|
+
/** The canonical scene `effectLayers`. */
|
|
88
|
+
export declare function effectLayerKeys(listed: readonly unknown[], effects: Pick<EffectValues, SceneEffectKey>): SceneEffectKey[];
|
|
35
89
|
/**
|
|
36
90
|
* Composition order, bottom to top.
|
|
37
91
|
* Display-only: the desktop chain's `rebuild()` is the order that runs — a stage moved there moves here too.
|
|
38
92
|
*/
|
|
39
|
-
export declare const
|
|
40
|
-
/**
|
|
41
|
-
export declare
|
|
93
|
+
export declare const ALL_EFFECT_STACK_ORDER: readonly EffectKey[];
|
|
94
|
+
/** Scene composition order, retained under its existing SDK name. */
|
|
95
|
+
export declare const EFFECT_STACK_ORDER: readonly SceneEffectKey[];
|
|
96
|
+
/** Layer composition order before the result joins the scene. */
|
|
97
|
+
export declare const LAYER_EFFECT_STACK_ORDER: readonly LayerEffectKey[];
|
|
98
|
+
/** Heal only the requested effect keys, using the same parameter kinds as defaults and editors. */
|
|
99
|
+
export declare function healEffectValues<K extends EffectKey>(raw: unknown, keys: readonly K[]): Pick<EffectValues, K>;
|
|
100
|
+
/** Scene toggle defaults, independent of effects offered only on layers. */
|
|
101
|
+
export declare function defaultToggleEffects(): Pick<EffectValues, SceneEffectKey>;
|
|
@@ -1,18 +1,50 @@
|
|
|
1
|
-
//
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
1
|
+
// Scope and parameter metadata are plain data; labels and rendering stay with their consumers.
|
|
2
|
+
import { finiteOr, isRecord } from "./guards.js";
|
|
3
|
+
import { clamp, hexColorOr } from "./limits.js";
|
|
4
|
+
/** Supported owners of each toggle effect; scene and layer membership are independent. */
|
|
5
|
+
export const EFFECT_SCOPES = {
|
|
6
|
+
color: ['scene', 'layer'],
|
|
7
|
+
levels: ['scene', 'layer'],
|
|
8
|
+
colorWheels: ['scene', 'layer'],
|
|
9
|
+
colorShift: ['scene', 'layer'],
|
|
10
|
+
selectColors: ['scene', 'layer'],
|
|
11
|
+
blur: ['scene', 'layer'],
|
|
12
|
+
bloom: ['scene', 'layer'],
|
|
13
|
+
diffusion: ['scene', 'layer'],
|
|
14
|
+
dof: ['scene'],
|
|
15
|
+
chromaticAberration: ['scene'],
|
|
16
|
+
grain: ['scene'],
|
|
17
|
+
vignette: ['scene'],
|
|
18
|
+
rim: ['scene', 'layer'],
|
|
19
|
+
outline: ['scene', 'layer'],
|
|
20
|
+
dropShadow: ['scene', 'layer'],
|
|
21
|
+
pixelate: ['scene'],
|
|
22
|
+
glitch: ['scene'],
|
|
23
|
+
droplets: ['scene'],
|
|
24
|
+
rain: ['scene'],
|
|
25
|
+
snow: ['scene'],
|
|
26
|
+
};
|
|
27
|
+
export const EFFECT_KEYS = Object.keys(EFFECT_SCOPES);
|
|
28
|
+
function keysForScope(scope) {
|
|
29
|
+
return EFFECT_KEYS.filter((key) => EFFECT_SCOPES[key].includes(scope));
|
|
30
|
+
}
|
|
31
|
+
/** Older hosts advertise effect availability through the values present in their payload. */
|
|
32
|
+
export function availableEffectKeys(scope, effects) {
|
|
33
|
+
return keysForScope(scope).filter(key => effects[key] !== undefined);
|
|
34
|
+
}
|
|
35
|
+
/** Preserve the option shape advertised by the host when resetting or applying settings. */
|
|
36
|
+
export function supportedEffectParams(current, patch) {
|
|
37
|
+
return Object.fromEntries(Object.entries(patch).filter(([key]) => Object.hasOwn(current, key)));
|
|
38
|
+
}
|
|
39
|
+
/** Named modes distinguish the newer rim/outline size and bloom intensity units from older hosts. */
|
|
40
|
+
export function hasCurrentEffectFormat(effect, value) {
|
|
41
|
+
const field = effect === 'outline' ? 'quality' : effect === 'rim' || effect === 'bloom' ? 'mode' : null;
|
|
42
|
+
return field === null || Object.hasOwn(value, field);
|
|
43
|
+
}
|
|
44
|
+
export const SCENE_EFFECT_KEYS = keysForScope('scene');
|
|
45
|
+
/** Scene toggle keys; retained for existing SDK consumers. */
|
|
46
|
+
export const TOGGLE_EFFECT_KEYS = SCENE_EFFECT_KEYS;
|
|
47
|
+
export const LAYER_EFFECT_KEYS = keysForScope('layer');
|
|
16
48
|
// Declared string-indexed so generic call sites (slider loop, healing walk) iterate
|
|
17
49
|
// without erasure casts; `satisfies` still checks exact per-effect param parity here.
|
|
18
50
|
export const EFFECT_SPECS = {
|
|
@@ -25,18 +57,84 @@ export const EFFECT_SPECS = {
|
|
|
25
57
|
temperature: { default: 0, min: -100, max: 100, step: 1 },
|
|
26
58
|
tint: { default: 0, min: -100, max: 100, step: 1 },
|
|
27
59
|
},
|
|
60
|
+
levels: {
|
|
61
|
+
inputBlack: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
62
|
+
inputWhite: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
63
|
+
inputGamma: { default: 1, min: 0.1, max: 4, step: 0.01 },
|
|
64
|
+
outputBlack: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
65
|
+
outputWhite: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
66
|
+
inputBlackR: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
67
|
+
inputWhiteR: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
68
|
+
inputGammaR: { default: 1, min: 0.1, max: 4, step: 0.01 },
|
|
69
|
+
outputBlackR: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
70
|
+
outputWhiteR: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
71
|
+
inputBlackG: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
72
|
+
inputWhiteG: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
73
|
+
inputGammaG: { default: 1, min: 0.1, max: 4, step: 0.01 },
|
|
74
|
+
outputBlackG: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
75
|
+
outputWhiteG: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
76
|
+
inputBlackB: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
77
|
+
inputWhiteB: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
78
|
+
inputGammaB: { default: 1, min: 0.1, max: 4, step: 0.01 },
|
|
79
|
+
outputBlackB: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
80
|
+
outputWhiteB: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
81
|
+
},
|
|
82
|
+
colorWheels: {
|
|
83
|
+
lift: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
84
|
+
gamma: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
85
|
+
gain: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
86
|
+
shadows: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
87
|
+
midtones: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
88
|
+
highlights: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
89
|
+
shadowLimit: { default: 0.3, min: 0, max: 1, step: 0.01 },
|
|
90
|
+
highlightLimit: { default: 0.7, min: 0, max: 1, step: 0.01 },
|
|
91
|
+
},
|
|
92
|
+
colorShift: {
|
|
93
|
+
hueRed: { default: 0, min: -180, max: 180, step: 1, unit: '°' },
|
|
94
|
+
saturationRed: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
95
|
+
luminanceRed: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
96
|
+
luminanceSaturationRed: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
97
|
+
hueYellow: { default: 0, min: -180, max: 180, step: 1, unit: '°' },
|
|
98
|
+
saturationYellow: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
99
|
+
luminanceYellow: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
100
|
+
luminanceSaturationYellow: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
101
|
+
hueGreen: { default: 0, min: -180, max: 180, step: 1, unit: '°' },
|
|
102
|
+
saturationGreen: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
103
|
+
luminanceGreen: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
104
|
+
luminanceSaturationGreen: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
105
|
+
hueCyan: { default: 0, min: -180, max: 180, step: 1, unit: '°' },
|
|
106
|
+
saturationCyan: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
107
|
+
luminanceCyan: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
108
|
+
luminanceSaturationCyan: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
109
|
+
hueBlue: { default: 0, min: -180, max: 180, step: 1, unit: '°' },
|
|
110
|
+
saturationBlue: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
111
|
+
luminanceBlue: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
112
|
+
luminanceSaturationBlue: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
113
|
+
hueMagenta: { default: 0, min: -180, max: 180, step: 1, unit: '°' },
|
|
114
|
+
saturationMagenta: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
115
|
+
luminanceMagenta: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
116
|
+
luminanceSaturationMagenta: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
117
|
+
},
|
|
118
|
+
selectColors: {
|
|
119
|
+
hueRange: { default: 0.08, min: 0, max: 0.5, step: 0.01 },
|
|
120
|
+
saturationRange: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
121
|
+
brightnessRange: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
122
|
+
saturation: { default: -1, min: -1, max: 1, step: 0.01 },
|
|
123
|
+
blend: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
124
|
+
},
|
|
125
|
+
blur: {
|
|
126
|
+
radius: { default: 8, min: 0, max: 64, step: 0.5, unit: 'px' },
|
|
127
|
+
},
|
|
28
128
|
bloom: {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
streakAngle: { default: 0, min: -90, max: 90, step: 1, unit: '°' },
|
|
39
|
-
darken: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
129
|
+
intensity: { default: 0, min: 0, max: 10, step: 0.01 },
|
|
130
|
+
threshold: { default: 0.5, min: 0, max: 2, step: 0.01 },
|
|
131
|
+
thresholdSmooth: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
132
|
+
radius: { default: 1, min: 0, max: 6, step: 0.01 },
|
|
133
|
+
saturation: { default: 0, min: -1, max: 1, step: 0.01 },
|
|
134
|
+
opacity: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
135
|
+
starRays: { default: 3, min: 1, max: 6, step: 1 },
|
|
136
|
+
starAngle: { default: 0, min: 0, max: 360, step: 1, unit: '°' },
|
|
137
|
+
colorTolerance: { default: 0.5, min: 0.01, max: 1, step: 0.01 },
|
|
40
138
|
},
|
|
41
139
|
// Shoost's diffusion (its Kino bloom variant, sliders Radius/Intensity/
|
|
42
140
|
// Contrast→threshold): screen-composited, so its Opacity slider folds into
|
|
@@ -51,8 +149,7 @@ export const EFFECT_SPECS = {
|
|
|
51
149
|
/** World metres of acceptably-sharp depth around the focus plane. */
|
|
52
150
|
focusRange: { default: 2, min: 0.1, max: 10, step: 0.01 },
|
|
53
151
|
},
|
|
54
|
-
// VTube Studio's chromatic_aberration surface: strength + blur edges
|
|
55
|
-
// latter continuous like rim.bothSides (VTS fades the same shader uniform).
|
|
152
|
+
// VTube Studio's chromatic_aberration surface: strength + continuous blur edges.
|
|
56
153
|
chromaticAberration: {
|
|
57
154
|
strength: { default: 0.2, min: 0, max: 1, step: 0.01 },
|
|
58
155
|
blurEdges: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
@@ -64,28 +161,16 @@ export const EFFECT_SPECS = {
|
|
|
64
161
|
darkness: { default: 0.5, min: 0, max: 1, step: 0.01 },
|
|
65
162
|
offset: { default: 0.5, min: 0, max: 1, step: 0.01 },
|
|
66
163
|
},
|
|
67
|
-
// Shoost's rim-light ranges where the control carried over (size, angle,
|
|
68
|
-
// opacity→intensity); the rest follows VTube Studio's backlight. New params
|
|
69
|
-
// default neutral (omni 0, limit 1, darken 0) so healed scenes keep their look.
|
|
70
164
|
rim: {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
brightnessLimit: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
78
|
-
darken: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
79
|
-
},
|
|
80
|
-
// VTube Studio's backlight outline block: stripe count/speed/curve ranges are
|
|
81
|
-
// VTS's; size is ours (px, like rim) instead of VTS's normalized 0..1.
|
|
165
|
+
size: { default: 0.5, min: 0, max: 1, step: 0.01 },
|
|
166
|
+
brightness: { default: 0, min: 0, max: 5, step: 0.01 },
|
|
167
|
+
contrast: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
168
|
+
angle: { default: 0, min: -180, max: 180, step: 1, unit: '°' },
|
|
169
|
+
opacity: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
170
|
+
},
|
|
82
171
|
outline: {
|
|
83
|
-
size: { default:
|
|
172
|
+
size: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
84
173
|
opacity: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
85
|
-
stripes: { default: 0.5, min: 0, max: 1, step: 0.01 },
|
|
86
|
-
stripeMix: { default: 1, min: 0, max: 1, step: 0.01 },
|
|
87
|
-
stripeSpeed: { default: 0.2, min: -1, max: 1, step: 0.01 },
|
|
88
|
-
stripeCurve: { default: 0, min: 0, max: 1, step: 0.01 },
|
|
89
174
|
},
|
|
90
175
|
// VTube Studio's backlight shadow: an offset silhouette copy. VTS hides it at
|
|
91
176
|
// zero offset; ours defaults to a visible down-right cast so enabling shows it.
|
|
@@ -93,6 +178,7 @@ export const EFFECT_SPECS = {
|
|
|
93
178
|
opacity: { default: 0.6, min: 0, max: 1, step: 0.01 },
|
|
94
179
|
offsetX: { default: 3, min: -20, max: 20, step: 0.5, digits: 1, unit: '%' },
|
|
95
180
|
offsetY: { default: 3, min: -20, max: 20, step: 0.5, digits: 1, unit: '%' },
|
|
181
|
+
size: { default: 0, min: 0, max: 64, step: 0.5, unit: 'px' },
|
|
96
182
|
},
|
|
97
183
|
pixelate: {
|
|
98
184
|
// Pixels per block; past ~64 the frame is a handful of tiles.
|
|
@@ -154,24 +240,127 @@ export const EFFECT_SPECS = {
|
|
|
154
240
|
* string param appear.
|
|
155
241
|
*/
|
|
156
242
|
export const EFFECT_COLOR_SPECS = {
|
|
243
|
+
colorWheels: {
|
|
244
|
+
liftColor: { default: '#ffffff' },
|
|
245
|
+
gammaColor: { default: '#ffffff' },
|
|
246
|
+
gainColor: { default: '#ffffff' },
|
|
247
|
+
shadowsColor: { default: '#ffffff' },
|
|
248
|
+
midtonesColor: { default: '#ffffff' },
|
|
249
|
+
highlightsColor: { default: '#ffffff' },
|
|
250
|
+
},
|
|
251
|
+
selectColors: {
|
|
252
|
+
color1: { default: '#ff0000' },
|
|
253
|
+
color2: { default: '#ffff00' },
|
|
254
|
+
color3: { default: '#00ff00' },
|
|
255
|
+
color4: { default: '#00ffff' },
|
|
256
|
+
color5: { default: '#0000ff' },
|
|
257
|
+
color6: { default: '#ff00ff' },
|
|
258
|
+
color7: { default: '#ffffff' },
|
|
259
|
+
color8: { default: '#808080' },
|
|
260
|
+
color9: { default: '#000000' },
|
|
261
|
+
color10: { default: '#ff8800' },
|
|
262
|
+
},
|
|
157
263
|
bloom: {
|
|
158
264
|
tint: { default: '#ffffff' },
|
|
159
|
-
|
|
160
|
-
|
|
265
|
+
color1: { default: '#ffffff' },
|
|
266
|
+
color2: { default: '#ffffff' },
|
|
267
|
+
color3: { default: '#ffffff' },
|
|
268
|
+
color4: { default: '#ffffff' },
|
|
269
|
+
color5: { default: '#ffffff' },
|
|
161
270
|
},
|
|
162
271
|
rim: {
|
|
163
272
|
color: { default: '#ffffff' },
|
|
164
273
|
},
|
|
165
274
|
outline: {
|
|
166
|
-
color: { default: '#
|
|
167
|
-
stripeColor: { default: '#000000' },
|
|
275
|
+
color: { default: '#000000' },
|
|
168
276
|
},
|
|
169
277
|
dropShadow: {
|
|
170
278
|
color: { default: '#000000' },
|
|
171
279
|
},
|
|
172
280
|
};
|
|
173
|
-
|
|
174
|
-
export const
|
|
281
|
+
/** Boolean defaults, validated alongside numeric and color parameters. */
|
|
282
|
+
export const EFFECT_BOOLEAN_SPECS = {
|
|
283
|
+
blur: { highQuality: { default: false } },
|
|
284
|
+
bloom: {
|
|
285
|
+
selectColors: { default: false },
|
|
286
|
+
invertColors: { default: false },
|
|
287
|
+
// Like Select Colors' first slot: with every pick off the mask is zero, so switching
|
|
288
|
+
// selection on would make the glow vanish rather than narrow.
|
|
289
|
+
color1Enabled: { default: true },
|
|
290
|
+
color2Enabled: { default: false },
|
|
291
|
+
color3Enabled: { default: false },
|
|
292
|
+
color4Enabled: { default: false },
|
|
293
|
+
color5Enabled: { default: false },
|
|
294
|
+
},
|
|
295
|
+
selectColors: {
|
|
296
|
+
invert: { default: false },
|
|
297
|
+
color1Enabled: { default: true },
|
|
298
|
+
color2Enabled: { default: false },
|
|
299
|
+
color3Enabled: { default: false },
|
|
300
|
+
color4Enabled: { default: false },
|
|
301
|
+
color5Enabled: { default: false },
|
|
302
|
+
color6Enabled: { default: false },
|
|
303
|
+
color7Enabled: { default: false },
|
|
304
|
+
color8Enabled: { default: false },
|
|
305
|
+
color9Enabled: { default: false },
|
|
306
|
+
color10Enabled: { default: false },
|
|
307
|
+
},
|
|
308
|
+
};
|
|
309
|
+
/** Enum defaults and allowed values. */
|
|
310
|
+
export const EFFECT_ENUM_SPECS = {
|
|
311
|
+
blur: { mode: { default: 'gaussian', values: ['gaussian', 'bokeh'] } },
|
|
312
|
+
bloom: { mode: { default: 'normal', values: ['normal', 'streak', 'star'] } },
|
|
313
|
+
rim: {
|
|
314
|
+
mode: { default: 'single', values: ['single', 'double', 'sharpenSingle', 'sharpenDouble'] },
|
|
315
|
+
blendMode: {
|
|
316
|
+
default: 'overlay',
|
|
317
|
+
values: [
|
|
318
|
+
'normal',
|
|
319
|
+
'darken',
|
|
320
|
+
'multiply',
|
|
321
|
+
'colorBurn',
|
|
322
|
+
'linearBurn',
|
|
323
|
+
'add',
|
|
324
|
+
'lighten',
|
|
325
|
+
'screen',
|
|
326
|
+
'colorDodge',
|
|
327
|
+
'overlay',
|
|
328
|
+
'softLight',
|
|
329
|
+
'hardLight',
|
|
330
|
+
'vividLight',
|
|
331
|
+
'linearLight',
|
|
332
|
+
'pinLight',
|
|
333
|
+
'hardMix',
|
|
334
|
+
'difference',
|
|
335
|
+
'exclusion',
|
|
336
|
+
'subtract',
|
|
337
|
+
'divide',
|
|
338
|
+
'hue',
|
|
339
|
+
'saturation',
|
|
340
|
+
'color',
|
|
341
|
+
'luminosity',
|
|
342
|
+
],
|
|
343
|
+
},
|
|
344
|
+
},
|
|
345
|
+
outline: { quality: { default: 'medium', values: ['low', 'medium', 'high'] } },
|
|
346
|
+
colorWheels: { mode: { default: 'liftGammaGain', values: ['liftGammaGain', 'shadowsMidtonesHighlights'] } },
|
|
347
|
+
};
|
|
348
|
+
/** Select the layer effects from any value set containing them. */
|
|
349
|
+
export function pickLayerEffects(effects) {
|
|
350
|
+
return Object.fromEntries(LAYER_EFFECT_KEYS.map(key => [key, effects[key]]));
|
|
351
|
+
}
|
|
352
|
+
/** The canonical per-item effect list, preserving disabled rows and including every enabled effect. */
|
|
353
|
+
export function layerEffectKeys(listed, effects) {
|
|
354
|
+
return canonicalKeys(LAYER_EFFECT_KEYS, listed, effects);
|
|
355
|
+
}
|
|
356
|
+
/** An independent, disabled set for a fresh source layer. */
|
|
357
|
+
export function defaultLayerEffects() {
|
|
358
|
+
return defaultsForKeys(LAYER_EFFECT_KEYS);
|
|
359
|
+
}
|
|
360
|
+
/** Whether a source needs its own effect pass. */
|
|
361
|
+
export function layerEffectsActive(effects) {
|
|
362
|
+
return LAYER_EFFECT_KEYS.some(key => effects[key].enabled);
|
|
363
|
+
}
|
|
175
364
|
/**
|
|
176
365
|
* Registry effects that render as scene geometry inside the scene pass rather
|
|
177
366
|
* than composing into the post chain. A new scene-space effect must join this
|
|
@@ -179,16 +368,20 @@ export const TOGGLE_EFFECT_KEYS = Object.keys(EFFECT_SPECS);
|
|
|
179
368
|
*/
|
|
180
369
|
export const SCENE_SPACE_EFFECT_KEYS = ['rain', 'snow'];
|
|
181
370
|
/** Registry effects the post chain composes — {@link TOGGLE_EFFECT_KEYS} minus the scene-space ones. */
|
|
182
|
-
export const POST_EFFECT_KEYS =
|
|
183
|
-
/**
|
|
371
|
+
export const POST_EFFECT_KEYS = SCENE_EFFECT_KEYS.filter(key => !SCENE_SPACE_EFFECT_KEYS.includes(key));
|
|
372
|
+
/** Registry order, junk dropped, every switched-on effect included — the rule both layer lists follow. */
|
|
373
|
+
function canonicalKeys(keys, listed, effects) {
|
|
374
|
+
return keys.filter(key => effects[key] !== undefined && (listed.includes(key) || effects[key].enabled));
|
|
375
|
+
}
|
|
376
|
+
/** The canonical scene `effectLayers`. */
|
|
184
377
|
export function effectLayerKeys(listed, effects) {
|
|
185
|
-
return
|
|
378
|
+
return canonicalKeys(SCENE_EFFECT_KEYS, listed, effects);
|
|
186
379
|
}
|
|
187
380
|
/**
|
|
188
381
|
* Composition order, bottom to top.
|
|
189
382
|
* Display-only: the desktop chain's `rebuild()` is the order that runs — a stage moved there moves here too.
|
|
190
383
|
*/
|
|
191
|
-
export const
|
|
384
|
+
export const ALL_EFFECT_STACK_ORDER = [
|
|
192
385
|
'rain',
|
|
193
386
|
'snow',
|
|
194
387
|
'dof',
|
|
@@ -199,24 +392,44 @@ export const EFFECT_STACK_ORDER = [
|
|
|
199
392
|
'bloom',
|
|
200
393
|
'diffusion',
|
|
201
394
|
'color',
|
|
395
|
+
'levels',
|
|
396
|
+
'colorWheels',
|
|
397
|
+
'colorShift',
|
|
398
|
+
'selectColors',
|
|
399
|
+
'blur',
|
|
202
400
|
'pixelate',
|
|
203
401
|
'glitch',
|
|
204
402
|
'droplets',
|
|
205
403
|
'grain',
|
|
206
404
|
'vignette',
|
|
207
405
|
];
|
|
208
|
-
/**
|
|
209
|
-
export
|
|
406
|
+
/** Scene composition order, retained under its existing SDK name. */
|
|
407
|
+
export const EFFECT_STACK_ORDER = ALL_EFFECT_STACK_ORDER.filter((key) => SCENE_EFFECT_KEYS.includes(key));
|
|
408
|
+
/** Layer composition order before the result joins the scene. */
|
|
409
|
+
export const LAYER_EFFECT_STACK_ORDER = ALL_EFFECT_STACK_ORDER.filter((key) => LAYER_EFFECT_KEYS.includes(key));
|
|
410
|
+
/** Heal only the requested effect keys, using the same parameter kinds as defaults and editors. */
|
|
411
|
+
export function healEffectValues(raw, keys) {
|
|
412
|
+
const src = isRecord(raw) ? raw : {};
|
|
210
413
|
const out = {};
|
|
211
|
-
for (const key of
|
|
212
|
-
const
|
|
414
|
+
for (const key of keys) {
|
|
415
|
+
const value = isRecord(src[key]) ? src[key] : {};
|
|
416
|
+
const fx = { enabled: value.enabled === true };
|
|
213
417
|
for (const [param, spec] of Object.entries(EFFECT_SPECS[key]))
|
|
214
|
-
fx[param] = spec.default;
|
|
418
|
+
fx[param] = clamp(finiteOr(value[param], spec.default), spec.min, spec.max);
|
|
215
419
|
for (const [param, spec] of Object.entries(EFFECT_COLOR_SPECS[key] ?? {}))
|
|
216
|
-
fx[param] = spec.default;
|
|
420
|
+
fx[param] = hexColorOr(value[param], spec.default);
|
|
421
|
+
for (const [param, spec] of Object.entries(EFFECT_BOOLEAN_SPECS[key] ?? {}))
|
|
422
|
+
fx[param] = typeof value[param] === 'boolean' ? value[param] : spec.default;
|
|
423
|
+
for (const [param, spec] of Object.entries(EFFECT_ENUM_SPECS[key] ?? {}))
|
|
424
|
+
fx[param] = typeof value[param] === 'string' && spec.values.includes(value[param]) ? value[param] : spec.default;
|
|
217
425
|
out[key] = fx;
|
|
218
426
|
}
|
|
219
|
-
// Runtime-built, invisible to TS; EFFECT_SPECS's satisfies check is what pins
|
|
220
|
-
// each entry's params to exactly SceneEffects[key].
|
|
221
427
|
return out;
|
|
222
428
|
}
|
|
429
|
+
function defaultsForKeys(keys) {
|
|
430
|
+
return healEffectValues(null, keys);
|
|
431
|
+
}
|
|
432
|
+
/** Scene toggle defaults, independent of effects offered only on layers. */
|
|
433
|
+
export function defaultToggleEffects() {
|
|
434
|
+
return defaultsForKeys(SCENE_EFFECT_KEYS);
|
|
435
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** VTube Studio hand inputs, extended with nizima LIVE's wrist Y rotation. */
|
|
2
|
+
export declare const HAND_INPUT_NAMES: readonly ["HandLeftFound", "HandLeftPositionX", "HandLeftPositionY", "HandLeftPositionZ", "HandLeftAngleX", "HandLeftAngleY", "HandLeftAngleZ", "HandLeftOpen", "HandLeftFinger_1_Thumb", "HandLeftFinger_2_Index", "HandLeftFinger_3_Middle", "HandLeftFinger_4_Ring", "HandLeftFinger_5_Pinky", "HandRightFound", "HandRightPositionX", "HandRightPositionY", "HandRightPositionZ", "HandRightAngleX", "HandRightAngleY", "HandRightAngleZ", "HandRightOpen", "HandRightFinger_1_Thumb", "HandRightFinger_2_Index", "HandRightFinger_3_Middle", "HandRightFinger_4_Ring", "HandRightFinger_5_Pinky", "BothHandsFound", "HandDistance"];
|
|
3
|
+
export type HandInputName = (typeof HAND_INPUT_NAMES)[number];
|
|
4
|
+
export type HandInputs = Partial<Record<HandInputName, number>>;
|
|
5
|
+
/** Whether an input uses the canonical hand vocabulary. */
|
|
6
|
+
export declare function isHandInputName(input: string): input is HandInputName;
|
|
7
|
+
/** Names nizima uses for VTS's numbered fingers and both-hands detection. */
|
|
8
|
+
export declare const NIZIMA_HAND_ALIASES: {
|
|
9
|
+
readonly HandLeftFingerThumb: "HandLeftFinger_1_Thumb";
|
|
10
|
+
readonly HandLeftFingerIndex: "HandLeftFinger_2_Index";
|
|
11
|
+
readonly HandLeftFingerMiddle: "HandLeftFinger_3_Middle";
|
|
12
|
+
readonly HandLeftFingerRing: "HandLeftFinger_4_Ring";
|
|
13
|
+
readonly HandLeftFingerPinky: "HandLeftFinger_5_Pinky";
|
|
14
|
+
readonly HandRightFingerThumb: "HandRightFinger_1_Thumb";
|
|
15
|
+
readonly HandRightFingerIndex: "HandRightFinger_2_Index";
|
|
16
|
+
readonly HandRightFingerMiddle: "HandRightFinger_3_Middle";
|
|
17
|
+
readonly HandRightFingerRing: "HandRightFinger_4_Ring";
|
|
18
|
+
readonly HandRightFingerPinky: "HandRightFinger_5_Pinky";
|
|
19
|
+
readonly HandBothFound: "BothHandsFound";
|
|
20
|
+
};
|
|
21
|
+
/** Canonicalize a hand name; aliases share canonical units on the plugin API. */
|
|
22
|
+
export declare function canonicalHandInputName(input: string): HandInputName | null;
|
|
23
|
+
/** Angles are degrees; positions and distance use VTS's ten-unit scale. */
|
|
24
|
+
export declare const HAND_INPUT_RANGES: {
|
|
25
|
+
readonly HandLeftFound: readonly [0, 1];
|
|
26
|
+
readonly HandLeftPositionX: readonly [-10, 10];
|
|
27
|
+
readonly HandLeftPositionY: readonly [-10, 10];
|
|
28
|
+
readonly HandLeftPositionZ: readonly [-10, 10];
|
|
29
|
+
readonly HandLeftAngleX: readonly [-180, 180];
|
|
30
|
+
readonly HandLeftAngleY: readonly [-90, 90];
|
|
31
|
+
readonly HandLeftAngleZ: readonly [-180, 180];
|
|
32
|
+
readonly HandLeftOpen: readonly [0, 1];
|
|
33
|
+
readonly HandLeftFinger_1_Thumb: readonly [0, 1];
|
|
34
|
+
readonly HandLeftFinger_2_Index: readonly [0, 1];
|
|
35
|
+
readonly HandLeftFinger_3_Middle: readonly [0, 1];
|
|
36
|
+
readonly HandLeftFinger_4_Ring: readonly [0, 1];
|
|
37
|
+
readonly HandLeftFinger_5_Pinky: readonly [0, 1];
|
|
38
|
+
readonly HandRightFound: readonly [0, 1];
|
|
39
|
+
readonly HandRightPositionX: readonly [-10, 10];
|
|
40
|
+
readonly HandRightPositionY: readonly [-10, 10];
|
|
41
|
+
readonly HandRightPositionZ: readonly [-10, 10];
|
|
42
|
+
readonly HandRightAngleX: readonly [-180, 180];
|
|
43
|
+
readonly HandRightAngleY: readonly [-90, 90];
|
|
44
|
+
readonly HandRightAngleZ: readonly [-180, 180];
|
|
45
|
+
readonly HandRightOpen: readonly [0, 1];
|
|
46
|
+
readonly HandRightFinger_1_Thumb: readonly [0, 1];
|
|
47
|
+
readonly HandRightFinger_2_Index: readonly [0, 1];
|
|
48
|
+
readonly HandRightFinger_3_Middle: readonly [0, 1];
|
|
49
|
+
readonly HandRightFinger_4_Ring: readonly [0, 1];
|
|
50
|
+
readonly HandRightFinger_5_Pinky: readonly [0, 1];
|
|
51
|
+
readonly BothHandsFound: readonly [0, 1];
|
|
52
|
+
readonly HandDistance: readonly [0, 10];
|
|
53
|
+
};
|