@laplace.live/persona-sdk 0.18.1 → 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.
Files changed (48) hide show
  1. package/README.md +4 -2
  2. package/dist/client/client.d.ts +1 -1
  3. package/dist/index.d.ts +9 -1
  4. package/dist/index.js +9 -1
  5. package/dist/values/bindings.d.ts +43 -0
  6. package/dist/values/bindings.js +1 -0
  7. package/dist/values/controller.d.ts +109 -0
  8. package/dist/values/controller.js +167 -0
  9. package/dist/values/curve.d.ts +5 -8
  10. package/dist/values/curve.js +16 -7
  11. package/dist/values/edit-history.d.ts +21 -0
  12. package/dist/values/edit-history.js +62 -0
  13. package/dist/values/effect-schema.d.ts +72 -12
  14. package/dist/values/effect-schema.js +279 -67
  15. package/dist/values/gltf-extensions.d.ts +20 -0
  16. package/dist/values/gltf-extensions.js +68 -0
  17. package/dist/values/guards.d.ts +2 -0
  18. package/dist/values/guards.js +5 -0
  19. package/dist/values/hands.d.ts +53 -0
  20. package/dist/values/hands.js +89 -0
  21. package/dist/values/hotkeys.d.ts +6 -0
  22. package/dist/values/hotkeys.js +11 -0
  23. package/dist/values/labels.d.ts +2 -0
  24. package/dist/values/labels.js +5 -1
  25. package/dist/values/limits.d.ts +19 -0
  26. package/dist/values/limits.js +27 -0
  27. package/dist/values/lipsync.d.ts +106 -0
  28. package/dist/values/lipsync.js +120 -0
  29. package/dist/values/locale.d.ts +2 -0
  30. package/dist/values/model-info.d.ts +66 -0
  31. package/dist/values/model-info.js +1 -0
  32. package/dist/values/stage-info.d.ts +27 -0
  33. package/dist/values/stage-info.js +1 -0
  34. package/dist/values/vrm-bindings.d.ts +14 -0
  35. package/dist/values/vrm-bindings.js +20 -0
  36. package/dist/wire/events.d.ts +1 -1
  37. package/dist/wire/methods.d.ts +210 -5
  38. package/dist/wire/protocol.d.ts +1 -1
  39. package/dist/wire/protocol.js +1 -1
  40. package/dist/wire/schemas.d.ts +116 -2
  41. package/dist/wire/schemas.js +40 -0
  42. package/dist/wire/types.d.ts +294 -131
  43. package/dist/wire/types.js +90 -12
  44. package/package.json +3 -17
  45. package/dist/effects.d.ts +0 -79
  46. package/dist/effects.js +0 -6
  47. package/dist/values/custom-effect.d.ts +0 -44
  48. package/dist/values/custom-effect.js +0 -136
@@ -1,4 +1,9 @@
1
+ import type { ControllerConfig } from '../values/controller.ts';
2
+ import type { EFFECT_SCOPES } from '../values/effect-schema.ts';
1
3
  import { type ArkitInputName } from '../values/arkit.ts';
4
+ import { type BaseControllerInputName, type ControllerInputName, type ControllerMovementConfig } from '../values/controller.ts';
5
+ import { type HandInputName } from '../values/hands.ts';
6
+ import { type LipSyncConfig, type LipSyncMode, type VoiceInputName } from '../values/lipsync.ts';
2
7
  export type ModelFormat = 'live2d' | 'vrm';
3
8
  /** Where an item came from: shipped with the app, or added by the user. */
4
9
  export type ContentOrigin = 'bundled' | 'user';
@@ -44,6 +49,8 @@ export interface AssetRef extends ContentRef {
44
49
  /** What the extension makes it — an object created from it starts on this kind. */
45
50
  kind: AssetKind;
46
51
  exists: boolean;
52
+ /** Source basename, with no directory. Absent on older hosts. */
53
+ file?: string;
47
54
  }
48
55
  /**
49
56
  * Content metadata decoupled from any on-disk file — local registry entries and
@@ -135,13 +142,25 @@ export interface SceneModelItem {
135
142
  instanceId: string;
136
143
  ref: ModelRef;
137
144
  visible: boolean;
145
+ /** Independent effects on this source, before scene effects; WebGPU only. */
146
+ effects: LayerEffects;
147
+ /** Added layer effects, including disabled rows whose tuning is retained. */
148
+ effectLayers: LayerEffectKey[];
138
149
  /**
139
150
  * Face source tracking this instance ({@link TrackingSourceConfig.id}); null = its face is untracked.
140
151
  * A dangling or disabled id behaves as null. One source may track several instances (mirroring).
141
152
  */
142
153
  faceSourceId: string | null;
143
- /** Body source (vmc) tracking this instance; null = its pose is untracked. New instances bind to each channel's default source. */
154
+ /** Body source tracking this instance; null = its pose is untracked. New instances bind to each channel's default source. */
144
155
  poseSourceId: string | null;
156
+ /** Hand source tracking this instance; null leaves hands untracked. */
157
+ handSourceId: string | null;
158
+ /** Track wrists and arms, or only fingers while the body source owns the arms. */
159
+ handTrackingMode: HandTrackingMode;
160
+ /** Whether microphone lipsync drives this model, independently of the face source assignment. */
161
+ lipSyncMode: LipSyncMode;
162
+ /** Opt-in controller movement, independent of parameter/bone bindings; disabled by default. */
163
+ controllerMovement: ControllerMovementConfig;
145
164
  live2d: ScreenPlacement;
146
165
  vrm: VrmPlacement;
147
166
  idleAnimation: boolean;
@@ -188,6 +207,8 @@ export type ObjectContent = {
188
207
  css: string;
189
208
  /** 2D only: composited behind or in front of the whole stage, not interleaved with other layers. */
190
209
  layer: WebLayer;
210
+ /** Close the page while the object is hidden and reload it on show, as an OBS browser source can. */
211
+ shutdownWhenHidden: boolean;
191
212
  } | {
192
213
  kind: 'capture';
193
214
  source: CaptureKind;
@@ -249,6 +270,10 @@ export interface SceneObjectItem {
249
270
  instanceId: string;
250
271
  name: string;
251
272
  visible: boolean;
273
+ /** Independent effects on this source, before scene effects; WebGPU only. */
274
+ effects: LayerEffects;
275
+ /** Added layer effects, including disabled rows whose tuning is retained. */
276
+ effectLayers: LayerEffectKey[];
252
277
  space: ObjectSpace;
253
278
  content: ObjectContent;
254
279
  place2d: Place2D;
@@ -271,9 +296,6 @@ export interface SceneBackground {
271
296
  color: string;
272
297
  imageAssetId: string | null;
273
298
  }
274
- export interface SceneBehavior {
275
- lookAtCursor: boolean;
276
- }
277
299
  /** VRM stage framing: the camera moves, the model does not. Angles in radians, distance in world units. */
278
300
  export interface OrbitTransform {
279
301
  azimuth: number;
@@ -333,28 +355,35 @@ export interface SceneFog {
333
355
  }
334
356
  /** Display transform applied after the scene renders. `none` keeps colors exactly as authored. */
335
357
  export type SceneToneMapping = 'none' | 'neutral' | 'aces' | 'agx';
336
- /**
337
- * Glow around bright pixels, with anamorphic streak flares on the side
338
- * (VTube Studio's Beautify-based bloom). `threshold` is the luminance floor;
339
- * `radius` widens the halo.
340
- */
358
+ /** Highlight glow in normal, streak, or star mode; color selection applies only to layer effects. */
341
359
  export interface SceneBloom {
342
360
  enabled: boolean;
361
+ mode: 'normal' | 'streak' | 'star';
362
+ /** UI offset: the glow's brightness multiplier is 1 + intensity. */
343
363
  intensity: number;
344
364
  threshold: number;
365
+ thresholdSmooth: number;
345
366
  radius: number;
346
- /** Halo tint (hex); white is untinted. */
367
+ saturation: number;
368
+ /** Glow color (hex); white is untinted. */
347
369
  tint: string;
348
- /** Anamorphic streak strength; 0 keeps the streak passes out of the graph. */
349
- streak: number;
350
- /** Luminance floor for the streak's own bright pass. */
351
- streakThreshold: number;
352
- /** Streak axis in degrees: 0 horizontal, ±90 vertical (VTS's vertical toggle, continuous). */
353
- streakAngle: number;
354
- /** Streak tint (hex); classic anamorphic flares are light blue. */
355
- streakTint: string;
356
- /** Darkens the avatar under the glow so highlights pop (VTS's model darken), 0..1. */
357
- darken: number;
370
+ opacity: number;
371
+ starRays: number;
372
+ starAngle: number;
373
+ selectColors: boolean;
374
+ invertColors: boolean;
375
+ /** Shared saturation/brightness tolerance; hue tolerance is fixed at 0.03. */
376
+ colorTolerance: number;
377
+ color1: string;
378
+ color2: string;
379
+ color3: string;
380
+ color4: string;
381
+ color5: string;
382
+ color1Enabled: boolean;
383
+ color2Enabled: boolean;
384
+ color3Enabled: boolean;
385
+ color4Enabled: boolean;
386
+ color5Enabled: boolean;
358
387
  }
359
388
  /**
360
389
  * Cinematic soft-focus veil (Shoost's diffusion, a Kino bloom variant): the
@@ -388,6 +417,116 @@ export interface SceneColorGrade {
388
417
  /** White balance along green↔magenta, −100..100 — the axis `temperature` leaves alone. */
389
418
  tint: number;
390
419
  }
420
+ /** Master and per-channel input/output levels; RGB channels run before master levels. */
421
+ export interface EffectLevels {
422
+ enabled: boolean;
423
+ inputBlack: number;
424
+ inputWhite: number;
425
+ inputGamma: number;
426
+ outputBlack: number;
427
+ outputWhite: number;
428
+ inputBlackR: number;
429
+ inputWhiteR: number;
430
+ inputGammaR: number;
431
+ outputBlackR: number;
432
+ outputWhiteR: number;
433
+ inputBlackG: number;
434
+ inputWhiteG: number;
435
+ inputGammaG: number;
436
+ outputBlackG: number;
437
+ outputWhiteG: number;
438
+ inputBlackB: number;
439
+ inputWhiteB: number;
440
+ inputGammaB: number;
441
+ outputBlackB: number;
442
+ outputWhiteB: number;
443
+ }
444
+ /** Color wheels in lift/gamma/gain or shadows/midtones/highlights mode. */
445
+ export interface EffectColorWheels {
446
+ enabled: boolean;
447
+ mode: 'liftGammaGain' | 'shadowsMidtonesHighlights';
448
+ lift: number;
449
+ liftColor: string;
450
+ gamma: number;
451
+ gammaColor: string;
452
+ gain: number;
453
+ gainColor: string;
454
+ shadows: number;
455
+ shadowsColor: string;
456
+ midtones: number;
457
+ midtonesColor: string;
458
+ highlights: number;
459
+ highlightsColor: string;
460
+ shadowLimit: number;
461
+ highlightLimit: number;
462
+ }
463
+ /** Six hue bands; hue offsets are degrees, other offsets are -1..1. */
464
+ export interface EffectColorShift {
465
+ enabled: boolean;
466
+ hueRed: number;
467
+ saturationRed: number;
468
+ luminanceRed: number;
469
+ luminanceSaturationRed: number;
470
+ hueYellow: number;
471
+ saturationYellow: number;
472
+ luminanceYellow: number;
473
+ luminanceSaturationYellow: number;
474
+ hueGreen: number;
475
+ saturationGreen: number;
476
+ luminanceGreen: number;
477
+ luminanceSaturationGreen: number;
478
+ hueCyan: number;
479
+ saturationCyan: number;
480
+ luminanceCyan: number;
481
+ luminanceSaturationCyan: number;
482
+ hueBlue: number;
483
+ saturationBlue: number;
484
+ luminanceBlue: number;
485
+ luminanceSaturationBlue: number;
486
+ hueMagenta: number;
487
+ saturationMagenta: number;
488
+ luminanceMagenta: number;
489
+ luminanceSaturationMagenta: number;
490
+ }
491
+ /** Preserve selected colors while adjusting saturation outside their HSV ranges. */
492
+ export interface EffectSelectColors {
493
+ enabled: boolean;
494
+ invert: boolean;
495
+ /** Hue distance in turns around the color wheel. */
496
+ hueRange: number;
497
+ saturationRange: number;
498
+ brightnessRange: number;
499
+ /** Saturation offset outside the selection; -1 makes it monochrome. */
500
+ saturation: number;
501
+ blend: number;
502
+ color1: string;
503
+ color1Enabled: boolean;
504
+ color2: string;
505
+ color2Enabled: boolean;
506
+ color3: string;
507
+ color3Enabled: boolean;
508
+ color4: string;
509
+ color4Enabled: boolean;
510
+ color5: string;
511
+ color5Enabled: boolean;
512
+ color6: string;
513
+ color6Enabled: boolean;
514
+ color7: string;
515
+ color7Enabled: boolean;
516
+ color8: string;
517
+ color8Enabled: boolean;
518
+ color9: string;
519
+ color9Enabled: boolean;
520
+ color10: string;
521
+ color10Enabled: boolean;
522
+ }
523
+ /** Gaussian or disk-shaped bokeh blur in output pixels. */
524
+ export interface EffectBlur {
525
+ enabled: boolean;
526
+ radius: number;
527
+ mode: 'gaussian' | 'bokeh';
528
+ highQuality: boolean;
529
+ }
391
530
  /** Lens fringing that grows toward frame edges (Unity PPv2's curve, the one VTube Studio wraps). */
392
531
  export interface SceneChromaticAberration {
393
532
  enabled: boolean;
@@ -468,55 +607,33 @@ export interface SceneDroplets {
468
607
  /** Specular glint on drops where the frame is transparent, so rain reads over the desktop (0 to 1). */
469
608
  glints: number;
470
609
  }
471
- /**
472
- * Screen-space rim light along the avatar silhouette (Shoost's layer rim light,
473
- * VTube Studio's backlight): coverage edges facing `angle` catch the glow.
474
- * Silhouette-driven — an opaque skybox leaves no edges to light.
475
- */
610
+ /** Blend modes shared with Shoost's rim light. */
611
+ export type EffectBlendMode = 'normal' | 'darken' | 'multiply' | 'colorBurn' | 'linearBurn' | 'add' | 'lighten' | 'screen' | 'colorDodge' | 'overlay' | 'softLight' | 'hardLight' | 'vividLight' | 'linearLight' | 'pinLight' | 'hardMix' | 'difference' | 'exclusion' | 'subtract' | 'divide' | 'hue' | 'saturation' | 'color' | 'luminosity';
612
+ /** Directional silhouette lighting, optionally sharpened or applied to both sides. */
476
613
  export interface SceneRim {
477
614
  enabled: boolean;
615
+ mode: 'single' | 'double' | 'sharpenSingle' | 'sharpenDouble';
616
+ blendMode: EffectBlendMode;
478
617
  /** Rim tint (hex). */
479
618
  color: string;
480
- /** Glow strength; past 1 overdrives into bloom territory. */
481
- intensity: number;
482
- /** Rim width in output pixels. */
619
+ /** Normalized rim width, 0..1. */
483
620
  size: number;
484
- /** Edge falloff: 0 a crisp line, 1 a wide soft fade. */
485
- softness: number;
486
- /** Light direction in degrees, compass-style: 0 lights from above, 90 from the right. */
621
+ brightness: number;
622
+ contrast: number;
623
+ /** Light direction in degrees, -180..180. */
487
624
  angle: number;
488
- /** How much the edge opposite the light glows too (0 to 1). */
489
- bothSides: number;
490
- /** Uniform glow on every edge regardless of `angle` (VTS's main backlight strength), 0..1. */
491
- omni: number;
492
- /** Ceiling the glow lightens pixels toward: 1 screens to white, lower protects highlights. */
493
- brightnessLimit: number;
494
- /** Darkens the avatar under the glow for contrast (VTS's model darken), 0..1. */
495
- darken: number;
625
+ opacity: number;
496
626
  }
497
- /**
498
- * Contour band hugging the avatar silhouette, with an optional animated stripe
499
- * pattern scrolling through it (VTube Studio's backlight outline). Silhouette-
500
- * driven like the rim light — it needs coverage edges to trace.
501
- */
627
+ /** Solid silhouette border with selectable edge sampling quality. */
502
628
  export interface SceneOutline {
503
629
  enabled: boolean;
630
+ quality: 'low' | 'medium' | 'high';
504
631
  /** Outline color (hex). */
505
632
  color: string;
506
- /** Stripe color (hex), painted over `color` where the stripe pattern lands. */
507
- stripeColor: string;
508
- /** Band thickness in output pixels. */
633
+ /** Normalized border thickness, 0..1. */
509
634
  size: number;
510
635
  /** Outline opacity 0..1. */
511
636
  opacity: number;
512
- /** Stripe density: 0 broad bands, 1 fine candy stripes. */
513
- stripes: number;
514
- /** Stripe visibility: 0 a solid outline, 1 full-strength stripes. */
515
- stripeMix: number;
516
- /** Stripe scroll speed; negative reverses the direction. */
517
- stripeSpeed: number;
518
- /** Bends the stripes into waves: 0 straight, 1 strongly curled. */
519
- stripeCurve: number;
520
637
  }
521
638
  /**
522
639
  * Hard-edged copy of the avatar silhouette cast behind it (VTube Studio's
@@ -532,6 +649,8 @@ export interface SceneDropShadow {
532
649
  offsetX: number;
533
650
  /** Vertical offset, percent of frame height; positive casts down. */
534
651
  offsetY: number;
652
+ /** Gaussian shadow softness in output pixels; 0 keeps a hard edge. */
653
+ size: number;
535
654
  }
536
655
  /** Compute-driven 3D rainfall: motion-blur streaks fall through the scene and splash on models, props, and the floor. */
537
656
  export interface SceneRain {
@@ -569,23 +688,19 @@ export interface SceneSnow {
569
688
  /** Flake opacity. */
570
689
  opacity: number;
571
690
  }
572
- /**
573
- * Post-processing over the rendered 3D frame. Everything off skips the effect
574
- * chain entirely. Deliberately flat: every toggle-plus-numbers effect sits at
575
- * the top level so tooling (defaults, healing, editors) can walk the effect
576
- * registry generically. Grouping is a panel concern, not a data one.
577
- */
578
- export interface SceneEffects {
579
- toneMapping: SceneToneMapping;
580
- /** Scene brightness multiplied in before the tone curve; 1 is neutral. Works in every mode, including `none`. */
581
- exposure: number;
691
+ /** Toggle effects independent of the scene or layer that owns their values. */
692
+ export interface EffectValues {
582
693
  bloom: SceneBloom;
583
694
  diffusion: SceneDiffusion;
584
695
  vignette: SceneVignette;
585
696
  color: SceneColorGrade;
697
+ levels: EffectLevels;
698
+ colorWheels: EffectColorWheels;
699
+ colorShift: EffectColorShift;
700
+ selectColors: EffectSelectColors;
701
+ blur: EffectBlur;
586
702
  chromaticAberration: SceneChromaticAberration;
587
703
  grain: SceneFilmGrain;
588
- lut: SceneLut;
589
704
  dof: SceneDepthOfField;
590
705
  rim: SceneRim;
591
706
  outline: SceneOutline;
@@ -596,30 +711,29 @@ export interface SceneEffects {
596
711
  rain: SceneRain;
597
712
  snow: SceneSnow;
598
713
  }
599
- /** Keys of {@link SceneEffects} that follow the `{ enabled } + params` pattern. */
600
- export type ToggleEffectKey = {
601
- [K in keyof SceneEffects]: SceneEffects[K] extends {
602
- enabled: boolean;
603
- } ? K : never;
604
- }[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>;
714
+ export type EffectKey = keyof EffectValues;
715
+ export type EffectScope = 'scene' | 'layer';
716
+ /** Effect availability comes from the catalog, independently for each scope. */
717
+ export type EffectKeyForScope<S extends EffectScope> = {
718
+ [K in EffectKey]: S extends (typeof EFFECT_SCOPES)[K][number] ? K : never;
719
+ }[EffectKey];
720
+ export type SceneEffectKey = EffectKeyForScope<'scene'>;
721
+ /** Scene toggle keys; retained for existing SDK consumers. */
722
+ export type ToggleEffectKey = SceneEffectKey;
723
+ /** Scene-wide toggles plus the display transform and color lookup table. */
724
+ export interface SceneEffects extends Pick<EffectValues, SceneEffectKey> {
725
+ toneMapping: SceneToneMapping;
726
+ /** Scene brightness multiplied in before the tone curve; 1 is neutral. Works in every mode, including `none`. */
727
+ exposure: number;
728
+ lut: SceneLut;
622
729
  }
730
+ /** Source-local effects, evaluated before the source joins the scene composition. */
731
+ export type LayerEffectKey = EffectKeyForScope<'layer'>;
732
+ export type LayerEffects = Pick<EffectValues, LayerEffectKey>;
733
+ /** Omitted effects and parameters retain their current values. */
734
+ export type LayerEffectsPatch = {
735
+ [K in LayerEffectKey]?: Partial<LayerEffects[K]>;
736
+ };
623
737
  /**
624
738
  * A 3D set's own suggested look — the fog and post settings it was authored against,
625
739
  * read from its root `LAPLACE_environment` extension and held on the scene for every client.
@@ -681,14 +795,6 @@ export interface SceneEnvironment {
681
795
  * switched off. Healing lists every switched-on effect, so a patch that switches one on adds its layer.
682
796
  */
683
797
  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
798
  }
693
799
  export interface Scene {
694
800
  id: string;
@@ -698,7 +804,6 @@ export interface Scene {
698
804
  /** Hotkey target and the default instance for model-scoped methods. null only when `items` holds no model. */
699
805
  primaryInstanceId: string | null;
700
806
  background: SceneBackground;
701
- behavior: SceneBehavior;
702
807
  vrmCamera: SceneCamera;
703
808
  /** Array order is display order only; live lights are keyed by id. */
704
809
  lights: SceneLight[];
@@ -719,7 +824,6 @@ export interface SceneState {
719
824
  */
720
825
  export interface ScenePatch {
721
826
  background?: SceneBackground;
722
- behavior?: SceneBehavior;
723
827
  vrmCamera?: SceneCamera;
724
828
  lights?: SceneLight[];
725
829
  environment?: SceneEnvironment;
@@ -728,11 +832,13 @@ export interface ScenePatch {
728
832
  * App-level features a client gates on (never version-sniff): `hello` and
729
833
  * `app.info` report them — the per-app mirror of {@link InstanceRuntime.capabilities}.
730
834
  */
731
- export declare const APP_CAPABILITIES: readonly ["storage", "speech", "shortcuts"];
835
+ export declare const APP_CAPABILITIES: readonly ["storage", "speech", "shortcuts", "controllers", "model-editing", "asset-inspection", "layer-effects"];
732
836
  export type AppCapability = (typeof APP_CAPABILITIES)[number];
733
837
  export declare function isAppCapability(v: unknown): v is AppCapability;
734
838
  /** What a loaded model instance can do; absent capabilities answer `unsupported-for-format`. */
735
839
  export type InstanceCapability = 'motions' | 'expressions' | 'placement-2d' | 'placement-3d' | 'mtoon' | 'idle-clips' | 'pose' | 'live2d-params'
840
+ /** `instance.setBreath`; the idle breathing loop is Cubism's, so VRM lacks it. */
841
+ | 'breath'
736
842
  /** `expression.setWeight`; Cubism expressions carry no user-settable weight, so Live2D lacks it. */
737
843
  | 'expression-weights'
738
844
  /** `speech.play` lip-sync; engine-dependent, so gate on the runtime, not the format. */
@@ -752,6 +858,8 @@ export interface InstanceRuntime {
752
858
  capabilities: InstanceCapability[];
753
859
  }
754
860
  export interface MotionGroup {
861
+ /** Whether this group loops; absent on older hosts. */
862
+ looping?: boolean;
755
863
  group: string;
756
864
  files: string[];
757
865
  }
@@ -776,20 +884,7 @@ export interface AnchorOption {
776
884
  anchor: AttachAnchor;
777
885
  label: string;
778
886
  }
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
- }
887
+ export type { ModelInfo } from '../values/model-info.ts';
793
888
  export interface Hotkey {
794
889
  id: string;
795
890
  name: string;
@@ -836,17 +931,38 @@ export interface ExpressionPersistence {
836
931
  export type JsonValue = string | number | boolean | null | JsonValue[] | {
837
932
  [key: string]: JsonValue;
838
933
  };
839
- export declare const TRACKING_SOURCE_IDS: readonly ["vts-ios", "ifacialmocap"];
934
+ export declare const TRACKING_SOURCE_IDS: readonly ["persona-ios", "ifacialmocap", "vts-ios"];
840
935
  export type TrackingSourceId = (typeof TRACKING_SOURCE_IDS)[number];
841
936
  /** Body-pose protocols. Every one so far is UDP with a configurable port. */
842
- export declare const POSE_SOURCE_IDS: readonly ["vmc"];
937
+ export declare const POSE_SOURCE_IDS: readonly ["vmc", "mocopi"];
843
938
  export type PoseSourceId = (typeof POSE_SOURCE_IDS)[number];
844
939
  export type TrackingStatus = 'off' | 'waiting' | 'tracking' | 'no-face';
845
940
  export type PoseStatus = 'off' | 'waiting' | 'tracking';
846
- /** Every protocol a tracking source instance can speak; face kinds plus the body (vmc) kind. */
847
- export declare const TRACKING_SOURCE_KINDS: readonly ["vts-ios", "ifacialmocap", "vmc"];
941
+ /** Every protocol a tracking source instance can speak; face and body kinds. */
942
+ export declare const TRACKING_SOURCE_KINDS: readonly ["persona-ios", "ifacialmocap", "vts-ios", "vmc", "mocopi", "mediapipe"];
848
943
  export type TrackingSourceKind = (typeof TRACKING_SOURCE_KINDS)[number];
849
- /** Whether a source kind feeds the face channel (vmc is the body channel). */
944
+ export declare const TRACKING_CHANNELS: readonly ["face", "pose", "hands"];
945
+ export type TrackingChannel = (typeof TRACKING_CHANNELS)[number];
946
+ /** The scene-item binding each channel reads and writes. */
947
+ export declare const TRACKING_CHANNEL_FIELDS: {
948
+ readonly face: "faceSourceId";
949
+ readonly pose: "poseSourceId";
950
+ readonly hands: "handSourceId";
951
+ };
952
+ export declare const HAND_TRACKING_MODES: readonly ["arms", "fingers"];
953
+ export type HandTrackingMode = (typeof HAND_TRACKING_MODES)[number];
954
+ export declare function isHandTrackingMode(v: unknown): v is HandTrackingMode;
955
+ /** The shared webcam source's enabled inference tasks and camera configuration. */
956
+ export interface MediaPipeConfig {
957
+ deviceId: string;
958
+ mirror: boolean;
959
+ face: boolean;
960
+ hands: boolean;
961
+ body: boolean;
962
+ delegate: 'CPU' | 'GPU';
963
+ }
964
+ export declare const DEFAULT_MEDIAPIPE_CONFIG: Readonly<MediaPipeConfig>;
965
+ /** Whether a source kind uses a network face receiver. */
850
966
  export declare function isFaceSourceKind(kind: TrackingSourceKind): kind is TrackingSourceId;
851
967
  /**
852
968
  * One configured tracking source instance. Several can run at once — one per person —
@@ -860,12 +976,40 @@ export interface TrackingSourceConfig {
860
976
  enabled: boolean;
861
977
  /**
862
978
  * 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 vmc (its senders pick the port).
979
+ * by a pinned instance of the same kind. Ignored by body sources (their senders pick the port).
864
980
  */
865
981
  phoneIp: string | null;
866
- /** vmc only: the UDP port this instance listens on. Null on face kinds — they bind per protocol. */
982
+ /**
983
+ * The UDP port this instance listens on: vmc, mocopi, and ifacialmocap (its receive port — the phone's
984
+ * Send Port must match). Null on persona-ios and vts-ios, whose ports the protocol fixes.
985
+ */
867
986
  port: number | null;
987
+ /** Present only on the shared webcam source. */
988
+ mediapipe?: MediaPipeConfig;
989
+ }
990
+ /** Whether a source uses a network body receiver. */
991
+ export declare function isPoseSource(source: TrackingSourceConfig): source is TrackingSourceConfig & {
992
+ kind: PoseSourceId;
993
+ };
994
+ /** The channels a kind can supply; the webcam's are further gated by its task switches. */
995
+ export declare function sourceKindChannels(kind: TrackingSourceKind): readonly TrackingChannel[];
996
+ /** Whether this source can supply a channel; {@link sourceChannelEnabled} folds in the switches. */
997
+ export declare function sourceSupportsChannel(source: TrackingSourceConfig, channel: TrackingChannel): boolean;
998
+ /** The face and body master switches; they gate network sources only. */
999
+ export interface ChannelMasters {
1000
+ face: boolean;
1001
+ pose: boolean;
868
1002
  }
1003
+ /**
1004
+ * Whether a source feeds a channel right now: its own switch, its task, and — for a network
1005
+ * face or body source — the channel master. Webcam tasks and hands answer to the source switch alone.
1006
+ */
1007
+ export declare function sourceChannelEnabled(source: TrackingSourceConfig, channel: TrackingChannel, masters: ChannelMasters): boolean;
1008
+ /**
1009
+ * Whether another source already holds `port` and would contend for it. iFacialMocap instances
1010
+ * share one socket per port (frames demux by phone); every other pairing EADDRINUSEs a listener.
1011
+ */
1012
+ export declare function trackingPortTaken(sources: readonly TrackingSourceConfig[], kind: TrackingSourceKind, port: number, excludeId?: string): boolean;
869
1013
  export declare const EFFECTS_QUALITY_LEVELS: readonly ["low", "medium", "high"];
870
1014
  export type EffectsQuality = (typeof EFFECTS_QUALITY_LEVELS)[number];
871
1015
  /**
@@ -873,11 +1017,22 @@ export type EffectsQuality = (typeof EFFECTS_QUALITY_LEVELS)[number];
873
1017
  * to the nearest preset by the app, so a picker offering other values would lie.
874
1018
  */
875
1019
  export declare const FPS_LIMIT_PRESETS: readonly [0, 15, 30, 60, 90];
1020
+ /** A stage window content size in device-independent px — what the desktop's window bounds report. */
1021
+ export interface StageSize {
1022
+ width: number;
1023
+ height: number;
1024
+ }
876
1025
  /** The curated settings surface the API exposes — never the raw store shape. */
877
1026
  export interface Settings {
1027
+ /** Absent on hosts without microphone lipsync. */
1028
+ lipSync?: LipSyncConfig;
1029
+ /** Absent on hosts without remote controller management. */
1030
+ controller?: ControllerConfig;
878
1031
  /** `alwaysOnTop` floats the control-panel window, never the stage. */
879
1032
  window: {
880
1033
  alwaysOnTop: boolean;
1034
+ /** Read-only; absent on older desktops. */
1035
+ stageSize?: StageSize;
881
1036
  };
882
1037
  ui: {
883
1038
  trayVisible: boolean;
@@ -887,14 +1042,17 @@ export interface Settings {
887
1042
  fpsLimit: number;
888
1043
  selectionOutline: boolean;
889
1044
  effectsQuality: EffectsQuality;
1045
+ /** Absent on older hosts. */
1046
+ renderScale?: number;
1047
+ live2dEngine?: 'pixi' | 'three';
890
1048
  };
891
- /** `source` mirrors the first face source's kind — the pre-multi-source field, kept for old clients. */
1049
+ /** `enabled` gates network face sources; `source` mirrors the first one's kind for old clients. */
892
1050
  tracking: {
893
1051
  enabled: boolean;
894
1052
  source: TrackingSourceId;
895
1053
  sources: TrackingSourceConfig[];
896
1054
  };
897
- /** `source`/`port` mirror the first vmc source — the pre-multi-source fields, kept for old clients. */
1055
+ /** `enabled` gates network body sources; `source`/`port` mirror the first one's values for old clients. */
898
1056
  pose: {
899
1057
  enabled: boolean;
900
1058
  source: PoseSourceId;
@@ -902,6 +1060,8 @@ export interface Settings {
902
1060
  };
903
1061
  }
904
1062
  export interface SettingsPatch {
1063
+ lipSync?: Partial<LipSyncConfig>;
1064
+ controller?: Partial<Pick<ControllerConfig, 'enabled'>>;
905
1065
  window?: {
906
1066
  alwaysOnTop?: boolean;
907
1067
  };
@@ -913,17 +1073,19 @@ export interface SettingsPatch {
913
1073
  fpsLimit?: number;
914
1074
  selectionOutline?: boolean;
915
1075
  effectsQuality?: EffectsQuality;
1076
+ renderScale?: number;
1077
+ live2dEngine?: 'pixi' | 'three';
916
1078
  };
917
1079
  }
918
1080
  /** VTS's input vocabulary, plus `JawOpen` — the derived half of {@link INPUT_NAMES}. */
919
1081
  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
1082
  type VtsInputName = (typeof VTS_INPUT_NAMES)[number];
921
1083
  /**
922
- * The valid `id`s for `input` inject targets, and the names a model's `.vtube.json`
923
- * references: VTS's derived vocabulary plus every raw ARKit channel.
1084
+ * Default input vocabulary: face and hand inputs, raw ARKit channels and controller profile 1.
1085
+ * Additional controller profile ids are accepted by isInputName without appearing in this list.
924
1086
  */
925
- export declare const INPUT_NAMES: readonly InputName[];
926
- export type InputName = VtsInputName | ArkitInputName;
1087
+ export declare const INPUT_NAMES: readonly (VtsInputName | HandInputName | VoiceInputName | ArkitInputName | BaseControllerInputName)[];
1088
+ export type InputName = VtsInputName | HandInputName | VoiceInputName | ArkitInputName | ControllerInputName;
927
1089
  /** Whether an untrusted string names a tracking input — the guard every wire boundary needs. */
928
1090
  export declare function isInputName(v: string): v is InputName;
929
1091
  /**
@@ -948,10 +1110,12 @@ export declare const BINDING_INPUT_NAMES: readonly BindingInput[];
948
1110
  /** The id an input is read as: its ARKit twin when it has one, else itself. */
949
1111
  export declare function arkitTwinOf(input: InputName): BindingInput;
950
1112
  /**
951
- * Each input's natural span — the units a sender should write, and the input range a new
952
- * binding starts from. Head angles are **degrees**; the rest are unitless.
1113
+ * Default inputs' natural spans. Use getInputRange for a dynamically numbered controller input.
1114
+ * Head angles are degrees; the rest are unitless.
953
1115
  */
954
- export declare const INPUT_RANGES: Record<InputName, readonly [number, number]>;
1116
+ export declare const INPUT_RANGES: Record<VtsInputName | HandInputName | VoiceInputName | ArkitInputName | BaseControllerInputName, readonly [number, number]>;
1117
+ /** Natural span of any valid input, including dynamically numbered controller profiles. */
1118
+ export declare function getInputRange(name: InputName): readonly [number, number];
955
1119
  /**
956
1120
  * What an injected value drives:
957
1121
  * - `input` — a VTS-vocabulary tracking input (`MouthOpen`, `FaceAngleX`, …), mapped
@@ -972,4 +1136,3 @@ export interface InjectEntry extends InjectTarget {
972
1136
  /** 0..1 blend over whatever else drives the parameter; default 1. */
973
1137
  weight?: number;
974
1138
  }
975
- export {};