@lovelace_lol/polymer 0.0.13 → 0.0.15
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 +74 -44
- package/dist/index.d.ts +32 -81
- package/dist/index.js +585 -583
- package/dist/worker/agency-worker.js +523 -523
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -30,13 +30,10 @@ It retains the renderer lifecycle support and speech AU 103 in
|
|
|
30
30
|
the existing `JAW.pitch.aus` list in CC4's `compositeRotations`. LipSync can send
|
|
31
31
|
the AU through Animation and use its saved bone and morph outputs.
|
|
32
32
|
|
|
33
|
-
The CC4
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
object and saves its orientation as `modelRotation`. Hosts using
|
|
38
|
-
`getBodyControls` inherit the catalog labels and sections unless a profile
|
|
39
|
-
explicitly overrides them. Action IDs and bone motion stay unchanged.
|
|
33
|
+
The CC4 hip bend, twist and side-bend AUs rotate the mapped hip bone, carrying
|
|
34
|
+
both torso and legs. Import/setup rotation remains a model transform saved as
|
|
35
|
+
`modelRotation`. `getAUDescriptors()` reads each character's actual AU labels,
|
|
36
|
+
bone and morph bindings and supported outputs; editors use this data directly.
|
|
40
37
|
|
|
41
38
|
The character host restores `profile.meshes` visibility and material settings
|
|
42
39
|
through Embody when binding a model or applying `setProfile`. Explicit hidden
|
|
@@ -282,6 +279,44 @@ The host supplies the gesture library and may observe streams for diagnostics,
|
|
|
282
279
|
but Gesture's own scheduler is responsible for replacement, cancellation, and
|
|
283
280
|
completion cleanup before Animation owns the runtime side effect.
|
|
284
281
|
|
|
282
|
+
### Animation API removal
|
|
283
|
+
|
|
284
|
+
Animation no longer exports `dispatch` or `AnimationDispatch`, and the character
|
|
285
|
+
`dispatch({ agency: "animation", ... })` envelope is rejected. Other agencies
|
|
286
|
+
retain their dispatch APIs. Hosts use the character's existing Animation agency:
|
|
287
|
+
|
|
288
|
+
```js
|
|
289
|
+
const animation = agencies.agency("animation");
|
|
290
|
+
animation.loadBakedClips();
|
|
291
|
+
animation.playBaked("Walk", { loop: true });
|
|
292
|
+
animation.pauseBaked("Walk");
|
|
293
|
+
animation.resumeBaked("Walk");
|
|
294
|
+
animation.seekBaked("Walk", 0);
|
|
295
|
+
animation.updateBakedParams("Walk", { intensityScale: 0.5 });
|
|
296
|
+
animation.stopBaked("Walk");
|
|
297
|
+
animation.prepareSnippet(snippet); // Forces autoPlay: false.
|
|
298
|
+
animation.resumeSnippet(snippet.name);
|
|
299
|
+
animation.pauseSnippet(snippet.name);
|
|
300
|
+
animation.removeSnippet(snippet.name);
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
`clearSnippets()` removes all scheduled snippets, including peer speech/gesture
|
|
304
|
+
work, while preserving baked clips. `stopAllBaked()` stops tracked baked handles,
|
|
305
|
+
including held actions, while preserving snippets. These are whole-agency
|
|
306
|
+
controls, not owner-scoped preview cancellation.
|
|
307
|
+
|
|
308
|
+
Peer messages use `AnimationInput` on `animation.input.write(command)`. Character
|
|
309
|
+
society routing delivers to that port while preserving route admission and
|
|
310
|
+
trusted source attribution. Worker hosts send
|
|
311
|
+
`{ type: "animationInput", id, command }`, without native handles or Three objects.
|
|
312
|
+
Named controls and peer input use the same private planner/scheduler path.
|
|
313
|
+
|
|
314
|
+
This removes Animation dispatch; it does not complete issue #306. The separate
|
|
315
|
+
AnimationService compatibility API, its catalog/event projections and native
|
|
316
|
+
baked bypass remain migration work. Unified source/instance controls,
|
|
317
|
+
configuration/inspection adoption, account storage and regional priority are
|
|
318
|
+
not delivered by this API removal.
|
|
319
|
+
|
|
285
320
|
### Animation snippet looping
|
|
286
321
|
|
|
287
322
|
Animation snippets default to repeating when no loop preference is supplied.
|
|
@@ -421,19 +456,16 @@ action/composite mappings, and continuum pairs, then reconfigure the runtime. Au
|
|
|
421
456
|
remain authoritative across preset upgrades. Clearing a role makes its semantic
|
|
422
457
|
bone outputs dormant while preserving the rest of the profile.
|
|
423
458
|
|
|
424
|
-
The CC4 preset supplies
|
|
425
|
-
arms, hands/fingers, legs
|
|
426
|
-
|
|
427
|
-
profile
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
model omits optional bones, and allow users to repair its assignments.
|
|
435
|
-
|
|
436
|
-
Every configured Body action, including each direction of a signed control,
|
|
459
|
+
The CC4 preset supplies anatomical role bindings and AU mappings across torso,
|
|
460
|
+
head, arms, hands/fingers, legs and feet/toes. `engine.getAUDescriptors()` returns
|
|
461
|
+
metadata from the configured Rust profile/model. The standalone
|
|
462
|
+
`getAUDescriptors(profile, model)` query supports unbound authoring. Descriptors
|
|
463
|
+
include numeric AU IDs, directional pairs when configured, bilateral support,
|
|
464
|
+
actual bone/morph bindings, saved morph strength and availability diagnostics.
|
|
465
|
+
Applications use the normal AU setters and getters; clearing a pose means
|
|
466
|
+
releasing its owned AU values, balances and morph-strength overrides.
|
|
467
|
+
|
|
468
|
+
Every configured AU, including each direction of a signed control,
|
|
437
469
|
can drive authored left/right/center morph mappings. Morph strength scales
|
|
438
470
|
those outputs even when the action has no bone bindings. Persist the action's
|
|
439
471
|
`auToMorphs` and `auMixDefaults`, and retain its mesh category: head, eye, and
|
|
@@ -633,31 +665,29 @@ request correlation and opaque checkpoint helpers. See
|
|
|
633
665
|
composition interface, account/mount identity and scoped cleanup rules. These
|
|
634
666
|
contracts do not enable a feature runtime or persist conversation/run data.
|
|
635
667
|
|
|
636
|
-
###
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
`
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
`
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
are normalized `0..1`, balance is character-relative `-1` left / `+1` right, and
|
|
657
|
-
times are seconds. Unknown controls, unsupported directions and invalid tracks fail.
|
|
668
|
+
### AU pose capture and generated animations
|
|
669
|
+
|
|
670
|
+
A pose uses numeric AU values, character-relative balances and per-AU morph
|
|
671
|
+
weights. Hosts read `engine.getAUDescriptors()` for actual saved mappings and
|
|
672
|
+
use `getAU`, `getAUBalance` and `getAUMixWeight` to capture values, then their
|
|
673
|
+
corresponding setters to restore them. Host code validates a complete record
|
|
674
|
+
before applying it; Polymer adds no parallel named-control pose format.
|
|
675
|
+
|
|
676
|
+
`AnimationService.schedule` uses ordinary `curves` keyed by numeric AU ID for
|
|
677
|
+
both facial and body motion. A snippet may add `balanceMap` and `mixWeights`:
|
|
678
|
+
`{curves:{1001:[{time:0,intensity:0},{time:0.2,intensity:0.8}]},
|
|
679
|
+
balanceMap:{1001:-1},mixWeights:{1001:0.25}}`. Balance ranges from character-left
|
|
680
|
+
`-1` to character-right `+1`; morph weight changes tissue deformation without
|
|
681
|
+
attenuating the AU's bone movement. Embody compiles the saved bone/morph
|
|
682
|
+
mappings into native clips without changing live AU settings. Existing save,
|
|
683
|
+
pause/resume, held-final-pose, completion and removal behavior applies.
|
|
684
|
+
|
|
685
|
+
`LEGACY_BODY_CONTROL_AUS` is an immutable lookup for host loaders decoding old
|
|
686
|
+
persisted names to numeric AUs. It supplies no labels, availability, profile
|
|
687
|
+
configuration or runtime control behavior. New records use AU IDs directly.
|
|
658
688
|
|
|
659
689
|
Manual `setAU` / `transitionAU` selects one configured continuum direction:
|
|
660
690
|
nonzero input clears its opposite, negative input selects the opposite, and
|
|
661
691
|
zero releases only the named action. `setContinuum` controls both directions
|
|
662
|
-
explicitly.
|
|
663
|
-
|
|
692
|
+
explicitly. AU and individual morph previews share the same live state;
|
|
693
|
+
separate axes remain independent.
|
package/dist/index.d.ts
CHANGED
|
@@ -15,6 +15,7 @@ import type {
|
|
|
15
15
|
import type { GLTF } from 'three/examples/jsm/loaders/GLTFLoader.js';
|
|
16
16
|
import type { ThreeModelReferencePose as EmbodyModelReferencePose } from '@lovelace_lol/embody/three';
|
|
17
17
|
export type ThreeModelReferencePose = EmbodyModelReferencePose;
|
|
18
|
+
export type { AUDescriptor } from '@lovelace_lol/embody';
|
|
18
19
|
import type {
|
|
19
20
|
CharacterSceneRenderer,
|
|
20
21
|
CharacterSceneBackend,
|
|
@@ -268,67 +269,6 @@ export interface HumanoidCharacterizationResolution {
|
|
|
268
269
|
valid: boolean;
|
|
269
270
|
}
|
|
270
271
|
|
|
271
|
-
/** Semantic body actions reuse the AU bone/morph evaluator. VRM names identify targets. */
|
|
272
|
-
export interface BodyControlDefinition {
|
|
273
|
-
label: string;
|
|
274
|
-
section: string;
|
|
275
|
-
auId: number;
|
|
276
|
-
negativeAuId?: number | null;
|
|
277
|
-
bilateral: boolean;
|
|
278
|
-
roles: VRMHumanoidRole[];
|
|
279
|
-
order?: number;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
export interface BodyControlDescriptor {
|
|
283
|
-
id: string;
|
|
284
|
-
label: string;
|
|
285
|
-
section: string;
|
|
286
|
-
auId: number;
|
|
287
|
-
negativeAuId: number | null;
|
|
288
|
-
auIds: number[];
|
|
289
|
-
bilateral: boolean;
|
|
290
|
-
roles: VRMHumanoidRole[];
|
|
291
|
-
order: number;
|
|
292
|
-
boneBindings: Array<BoneBinding & { auId: number; boneName: string }>;
|
|
293
|
-
morphBindings: MorphTargetsBySide;
|
|
294
|
-
meshNames: string[];
|
|
295
|
-
hasBones: boolean;
|
|
296
|
-
hasMorphs: boolean;
|
|
297
|
-
isMixed: boolean;
|
|
298
|
-
available: boolean;
|
|
299
|
-
diagnostics: string[];
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
/** Pose values are normalized authored action amounts, never world Euler angles. */
|
|
303
|
-
export interface SemanticPoseChannel {
|
|
304
|
-
intensity: number;
|
|
305
|
-
/** -1 = character's left, 0 = both, +1 = character's right. */
|
|
306
|
-
balance?: number;
|
|
307
|
-
/** Morph contribution only; bone activation remains intensity. Defaults to profile. */
|
|
308
|
-
morphStrength?: number;
|
|
309
|
-
}
|
|
310
|
-
export interface SemanticPose {
|
|
311
|
-
version: 1;
|
|
312
|
-
controls: Array<{ controlId: string; positive?: SemanticPoseChannel; negative?: SemanticPoseChannel }>;
|
|
313
|
-
}
|
|
314
|
-
export interface SemanticPoseDirection {
|
|
315
|
-
auId: number; label: string; available: boolean; availableSides?: Array<'left' | 'right' | 'center'>; hasBones: boolean; hasMorphs: boolean; morphStrength: number;
|
|
316
|
-
}
|
|
317
|
-
export interface SemanticPoseControl {
|
|
318
|
-
id: string; label: string; section: string; roles: string[]; bilateral: boolean;
|
|
319
|
-
boneNames: string[]; morphNames: string[];
|
|
320
|
-
positive: SemanticPoseDirection; negative?: SemanticPoseDirection;
|
|
321
|
-
}
|
|
322
|
-
export interface SemanticAnimation {
|
|
323
|
-
version: 1;
|
|
324
|
-
durationSeconds: number;
|
|
325
|
-
tracks: Array<{ controlId: string; direction: 'positive' | 'negative'; balance?: number; morphStrength?: number;
|
|
326
|
-
keyframes: Array<{ time: number; intensity: number }> }>;
|
|
327
|
-
}
|
|
328
|
-
export interface SemanticAnimationOptions extends Record<string, unknown> {
|
|
329
|
-
faceCurves?: Record<string, Array<{ time: number; intensity: number; inherit?: boolean }>>;
|
|
330
|
-
}
|
|
331
|
-
|
|
332
272
|
export interface Profile {
|
|
333
273
|
name?: string;
|
|
334
274
|
animalType?: string;
|
|
@@ -370,8 +310,6 @@ export interface Profile {
|
|
|
370
310
|
disabledRegions?: string[];
|
|
371
311
|
hairPhysics?: HairPhysicsProfileConfig;
|
|
372
312
|
humanoidCharacterization?: HumanoidCharacterization;
|
|
373
|
-
/** Authored overrides may patch individual fields; null removes a preset control. */
|
|
374
|
-
bodyControls?: Record<string, Partial<BodyControlDefinition> | null>;
|
|
375
313
|
}
|
|
376
314
|
|
|
377
315
|
export interface ProfileRuntimeConfig extends Partial<Profile> {
|
|
@@ -699,16 +637,8 @@ export interface PolymerCharacterRuntime {
|
|
|
699
637
|
getAU(id: number): number;
|
|
700
638
|
/** Current procedural left/right balance (-1..1), or zero after clear. */
|
|
701
639
|
getAUBalance(id: number): number;
|
|
702
|
-
/**
|
|
703
|
-
|
|
704
|
-
getSemanticPoseCatalog(): SemanticPoseControl[];
|
|
705
|
-
captureSemanticPose(): SemanticPose;
|
|
706
|
-
validateSemanticPose(pose: SemanticPose): SemanticPose;
|
|
707
|
-
applySemanticPose(pose: SemanticPose): void;
|
|
708
|
-
validateSemanticAnimation(animation: SemanticAnimation, options?: SemanticAnimationOptions): void;
|
|
709
|
-
semanticAnimationToClip(name: string, animation: SemanticAnimation, options?: SemanticAnimationOptions): AnimationPlaybackHandle;
|
|
710
|
-
/** Reset configured body actions atomically; the next native mixer frame applies the pose. */
|
|
711
|
-
resetBodyControls(): void;
|
|
640
|
+
/** Saved AU metadata resolved against the configured profile and model. */
|
|
641
|
+
getAUDescriptors(): import('@lovelace_lol/embody').AUDescriptor[];
|
|
712
642
|
setContinuum(negAU: number, posAU: number, value: number, balance?: number): void;
|
|
713
643
|
getContinuum(negAU: number, posAU: number): number;
|
|
714
644
|
/** Mixer-timed live control; defaults to 200 ms. getAU reports its destination immediately. */
|
|
@@ -901,7 +831,9 @@ export declare function setHumanoidRoleBinding(profile: Profile, role: VRMHumano
|
|
|
901
831
|
export declare function setAUMorphTargets(profile: Profile, auId: number, side: 'left' | 'right' | 'center', targets: Array<string | number>): Profile;
|
|
902
832
|
export declare function resolveHumanoidCharacterization(profile: Profile): HumanoidCharacterizationResolution;
|
|
903
833
|
/** With a model, reports missing bone/morph targets against the actual scene. */
|
|
904
|
-
export
|
|
834
|
+
export { getAUDescriptors } from '@lovelace_lol/embody';
|
|
835
|
+
/** @deprecated Immutable decoder lookup for historical host records; never a live control catalog. */
|
|
836
|
+
export { LEGACY_BODY_CONTROL_AUS } from '@lovelace_lol/embody';
|
|
905
837
|
export declare const VISEME_KEYS: string[];
|
|
906
838
|
export declare const HAIR_COLOR_PRESETS: Record<string, HairColorAppearance>;
|
|
907
839
|
export declare const DEFAULT_HAIR_COLOR_APPEARANCE: HairColorAppearance;
|
|
@@ -1062,7 +994,7 @@ export interface AnimationAgencyConfig {
|
|
|
1062
994
|
runtimeConfig?: Record<string, unknown>;
|
|
1063
995
|
}
|
|
1064
996
|
|
|
1065
|
-
export type
|
|
997
|
+
export type AnimationInput =
|
|
1066
998
|
| {
|
|
1067
999
|
type: 'scheduleSnippet';
|
|
1068
1000
|
sourceAgency?: string;
|
|
@@ -1071,6 +1003,8 @@ export type AnimationDispatch =
|
|
|
1071
1003
|
}
|
|
1072
1004
|
| { type: 'seekSnippet'; sourceAgency?: string; name: string; offsetSec: number }
|
|
1073
1005
|
| { type: 'updateSnippet'; sourceAgency?: string; name: string; params: Record<string, unknown> }
|
|
1006
|
+
| { type: 'pauseSnippet'; sourceAgency?: string; name: string }
|
|
1007
|
+
| { type: 'resumeSnippet'; sourceAgency?: string; name: string; snippet?: PolymerAnimationSnippet; options?: { autoPlay?: boolean; [key: string]: unknown } }
|
|
1074
1008
|
| { type: 'removeSnippet'; sourceAgency?: string; name: string }
|
|
1075
1009
|
| { type: 'clear'; sourceAgency?: string }
|
|
1076
1010
|
| { type: 'loadBakedClips'; sourceAgency?: string; clips?: AnimationBakedClipInfo[] }
|
|
@@ -2571,11 +2505,10 @@ export interface BlinkAgency {
|
|
|
2571
2505
|
}
|
|
2572
2506
|
|
|
2573
2507
|
export interface AnimationAgency {
|
|
2574
|
-
input: PolymerInputStream<
|
|
2508
|
+
input: PolymerInputStream<AnimationInput>;
|
|
2575
2509
|
events: PolymerStream<PolymerDomainEvent>;
|
|
2576
|
-
dispatch(command: AnimationDispatch): void;
|
|
2577
2510
|
snapshot(): AnimationState;
|
|
2578
|
-
subscribeInput(listener: (event: { type: 'command'; agency: 'animation'; command:
|
|
2511
|
+
subscribeInput(listener: (event: { type: 'command'; agency: 'animation'; command: AnimationInput }) => void): () => void;
|
|
2579
2512
|
subscribeEvents(listener: (event: PolymerDomainEvent) => void): () => void;
|
|
2580
2513
|
/** Compatibility alias for events. Prefer subscribeEvents. */
|
|
2581
2514
|
subscribe(listener: (event: PolymerStatusEvent) => void): () => void;
|
|
@@ -2585,6 +2518,22 @@ export interface AnimationAgency {
|
|
|
2585
2518
|
seekSnippet(name: string, offsetSec: number): void;
|
|
2586
2519
|
updateSnippet(name: string, params: Record<string, unknown>): void;
|
|
2587
2520
|
removeSnippet(name: string): void;
|
|
2521
|
+
pauseSnippet(name: string): void;
|
|
2522
|
+
resumeSnippet(name: string, snippet?: PolymerAnimationSnippet, options?: { autoPlay?: boolean; [key: string]: unknown }): void;
|
|
2523
|
+
/** Build a private native handle without playing. Forces autoPlay: false. */
|
|
2524
|
+
prepareSnippet(snippet: PolymerAnimationSnippet, options?: { autoPlay?: boolean; [key: string]: unknown }): void;
|
|
2525
|
+
/** Remove all scheduled snippets in this agency, including peer-owned snippets. Does not stop baked clips. */
|
|
2526
|
+
clearSnippets(): void;
|
|
2527
|
+
/** Refresh the catalog from the runtime when omitted; does not start playback or fetch assets. */
|
|
2528
|
+
loadBakedClips(clips?: AnimationBakedClipInfo[]): void;
|
|
2529
|
+
playBaked(name: string, options?: Record<string, unknown>): void;
|
|
2530
|
+
stopBaked(name: string): void;
|
|
2531
|
+
pauseBaked(name: string): void;
|
|
2532
|
+
resumeBaked(name: string): void;
|
|
2533
|
+
seekBaked(name: string, offsetSec: number): void;
|
|
2534
|
+
updateBakedParams(name: string, params: Record<string, unknown>): void;
|
|
2535
|
+
/** Stop all baked handles tracked by this agency, including held actions. Does not remove snippets. */
|
|
2536
|
+
stopAllBaked(): void;
|
|
2588
2537
|
dispose(): void;
|
|
2589
2538
|
}
|
|
2590
2539
|
|
|
@@ -2787,8 +2736,7 @@ export type CharacterAgencyDispatch =
|
|
|
2787
2736
|
| { agency: 'conversation'; command: ConversationDispatch }
|
|
2788
2737
|
| { agency: 'tts'; command: TTSDispatch }
|
|
2789
2738
|
| { agency: 'lipSync'; command: LipSyncDispatch }
|
|
2790
|
-
| { agency: 'prosodic'; command: ProsodicDispatch }
|
|
2791
|
-
| { agency: 'animation'; command: AnimationDispatch };
|
|
2739
|
+
| { agency: 'prosodic'; command: ProsodicDispatch };
|
|
2792
2740
|
|
|
2793
2741
|
export interface CharacterAgencies {
|
|
2794
2742
|
input: PolymerInputStream<CharacterAgencyDispatch>;
|
|
@@ -2858,11 +2806,14 @@ export interface AIExpressionSnippetMetadata {
|
|
|
2858
2806
|
}
|
|
2859
2807
|
|
|
2860
2808
|
export interface Snippet {
|
|
2861
|
-
semanticAnimation?: SemanticAnimation;
|
|
2862
2809
|
name?: string;
|
|
2863
2810
|
au?: Array<{ id: string | number; t?: number; v?: number; time?: number; intensity?: number; inherit?: boolean }>;
|
|
2864
2811
|
viseme?: Array<{ key: string | number; t?: number; v?: number; time?: number; intensity?: number; inherit?: boolean }>;
|
|
2865
2812
|
curves?: Record<string, CurvePoint[]>;
|
|
2813
|
+
/** Per-AU character-relative balance, -1 left to +1 right; canonical clip input. */
|
|
2814
|
+
balanceMap?: Record<string, number>;
|
|
2815
|
+
/** Per-AU morph strength; does not attenuate the AU's bone contribution. */
|
|
2816
|
+
mixWeights?: Record<string, number>;
|
|
2866
2817
|
channels?: PolymerSnippetChannel[];
|
|
2867
2818
|
isPlaying?: boolean;
|
|
2868
2819
|
loop?: boolean;
|