@lovelace_lol/polymer 0.0.14 → 0.0.16

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 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 body-control catalog places hip bend, twist and side bend in **Whole
34
- body**, separate from the waist, spine and chest controls in **Torso**. These
35
- existing animation controls rotate the hip bone, which carries both torso and
36
- legs. They differ from import/setup rotation, which rotates the entire model
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
@@ -54,12 +51,10 @@ collaboration, scheduler, side-effect, stream, and runtime-target rules.
54
51
  The Rust host's live-control release and mixer ownership contract is documented
55
52
  in [docs/live-control-ownership.md](docs/live-control-ownership.md).
56
53
 
57
- For gaze tracking, head following takes the full target turn from reference neutral,
58
- bounded by the profile's head AU limits;
59
- camera-facing preference requires `lockHeadToCamera: true`. With geometry-backed focus, live eye/head strength
60
- changes move continuously toward the latest value in [0, 1], including when a
61
- slider reverses direction. See the [eye-contact contract](docs/gaze-tracking-contract.md)
62
- for geometry, timing, channel ownership, and authored motion behavior.
54
+ The former Gaze and EyeHeadTracking agencies, runtime factories, and full-rig
55
+ clock-driven tests were retired in #300. Camera Context and User Perception
56
+ still publish sensing facts; this does not provide the retired gaze motor path.
57
+ The [eye-contact contract](docs/gaze-tracking-contract.md) is a historical reference.
63
58
 
64
59
  ## Camera and annotation runtime
65
60
 
@@ -459,19 +454,16 @@ action/composite mappings, and continuum pairs, then reconfigure the runtime. Au
459
454
  remain authoritative across preset upgrades. Clearing a role makes its semantic
460
455
  bone outputs dormant while preserving the rest of the profile.
461
456
 
462
- The CC4 preset supplies a complete role map and controls across torso, head,
463
- arms, hands/fingers, legs, and feet/toes. Bound UI controls use
464
- `engine.getBodyControls()` to read descriptors cached from the configured Rust
465
- profile/model, avoiding scene traversal and repeated profile parsing. The standalone
466
- `getBodyControls(profile, model)` query remains available for unbound authoring.
467
- `engine.resetBodyControls()` clears the configured catalog's action values and
468
- balances in one Rust call and applies one frame, preserving unrelated facial actions
469
- and morph-strength settings. Head, eye, and jaw controls
470
- share existing facial actuators; all controls use the existing AU/continuum
471
- host methods. Applications should show the full role inventory even when a
472
- model omits optional bones, and allow users to repair its assignments.
473
-
474
- Every configured Body action, including each direction of a signed control,
457
+ The CC4 preset supplies anatomical role bindings and AU mappings across torso,
458
+ head, arms, hands/fingers, legs and feet/toes. `engine.getAUDescriptors()` returns
459
+ metadata from the configured Rust profile/model. The standalone
460
+ `getAUDescriptors(profile, model)` query supports unbound authoring. Descriptors
461
+ include numeric AU IDs, directional pairs when configured, bilateral support,
462
+ actual bone/morph bindings, saved morph strength and availability diagnostics.
463
+ Applications use the normal AU setters and getters; clearing a pose means
464
+ releasing its owned AU values, balances and morph-strength overrides.
465
+
466
+ Every configured AU, including each direction of a signed control,
475
467
  can drive authored left/right/center morph mappings. Morph strength scales
476
468
  those outputs even when the action has no bone bindings. Persist the action's
477
469
  `auToMorphs` and `auMixDefaults`, and retain its mesh category: head, eye, and
@@ -566,6 +558,16 @@ the declarations into that staging directory. `pnpm verify` checks the
566
558
  source-only rule, validates the runtime exports and packed file list, and runs
567
559
  the CLJS and worker tests.
568
560
 
561
+ PR verification uses one concurrency group per PR, so a new revision cancels
562
+ obsolete work for that PR. Stable npm releases retain their serialized group and
563
+ are not canceled by new PR runs. Explicit preview requests remain grouped by
564
+ their requested SHA or ref.
565
+
566
+ Tests exercise Polymer's agency routing and runtime adapters. Pure Embody
567
+ behavior behind unchanged re-exports belongs in Embody; Polymer retains export
568
+ and declaration checks plus annotation constructor identity checks. Completed
569
+ gaze retirement does not need a separate test command or CI step.
570
+
569
571
  The package intentionally has no `prepare`, `install`, or `postinstall` build
570
572
  lifecycle. Consumers install an already-built npm release or a pkg.pr.new preview
571
573
  for a specific commit and therefore do not need Java, Shadow CLJS, or a local
@@ -671,31 +673,29 @@ request correlation and opaque checkpoint helpers. See
671
673
  composition interface, account/mount identity and scoped cleanup rules. These
672
674
  contracts do not enable a feature runtime or persist conversation/run data.
673
675
 
674
- ### Semantic pose capture and generated animations
675
-
676
- The Rust host exposes `getSemanticPoseCatalog()`, `captureSemanticPose()`,
677
- `validateSemanticPose(pose)` and `applySemanticPose(pose)`. The catalog follows
678
- the configured profile and actual model, including independent direction support,
679
- VRM role names, owned bone/morph names and authored default tissue strengths.
680
- Captures preserve both opposing directions, bilateral balance and morph strength;
681
- they represent manual semantic state, not inverse inference of a baked pose.
682
- Validation is atomic and lives in Embody. Known missing outputs may be saved for
683
- partial rigs; generation should offer only supported catalog directions.
684
-
685
- Normal `AnimationService.schedule` snippets may include `semanticAnimation`:
686
- `{version:1,durationSeconds,tracks:[{controlId,direction,balance?,morphStrength?,
687
- keyframes:[{time,intensity}]}]}`. Existing `curves` are non-Body facial AUs.
688
- Embody compiles both sets together into bone/morph tracks, preserving each tissue
689
- strength without changing live controls. Service save, pause, resume and cleanup
690
- use the existing snippet lifecycle. `validateSemanticAnimation(animation, options)`
691
- compiles without retaining clips. `semanticAnimationToClip(name, animation,
692
- options)` builds an ordinary playback handle; `options.faceCurves` adds facial
693
- curves for direct callers. IDs and direction labels come from the catalog, amounts
694
- are normalized `0..1`, balance is character-relative `-1` left / `+1` right, and
695
- times are seconds. Unknown controls, unsupported directions and invalid tracks fail.
676
+ ### AU pose capture and generated animations
677
+
678
+ A pose uses numeric AU values, character-relative balances and per-AU morph
679
+ weights. Hosts read `engine.getAUDescriptors()` for actual saved mappings and
680
+ use `getAU`, `getAUBalance` and `getAUMixWeight` to capture values, then their
681
+ corresponding setters to restore them. Host code validates a complete record
682
+ before applying it; Polymer adds no parallel named-control pose format.
683
+
684
+ `AnimationService.schedule` uses ordinary `curves` keyed by numeric AU ID for
685
+ both facial and body motion. A snippet may add `balanceMap` and `mixWeights`:
686
+ `{curves:{1001:[{time:0,intensity:0},{time:0.2,intensity:0.8}]},
687
+ balanceMap:{1001:-1},mixWeights:{1001:0.25}}`. Balance ranges from character-left
688
+ `-1` to character-right `+1`; morph weight changes tissue deformation without
689
+ attenuating the AU's bone movement. Embody compiles the saved bone/morph
690
+ mappings into native clips without changing live AU settings. Existing save,
691
+ pause/resume, held-final-pose, completion and removal behavior applies.
692
+
693
+ `LEGACY_BODY_CONTROL_AUS` is an immutable lookup for host loaders decoding old
694
+ persisted names to numeric AUs. It supplies no labels, availability, profile
695
+ configuration or runtime control behavior. New records use AU IDs directly.
696
696
 
697
697
  Manual `setAU` / `transitionAU` selects one configured continuum direction:
698
698
  nonzero input clears its opposite, negative input selects the opposite, and
699
699
  zero releases only the named action. `setContinuum` controls both directions
700
- explicitly. Body and individual AU/morph previews therefore share the same
701
- live state; separate axes remain independent.
700
+ explicitly. AU and individual morph previews share the same live state;
701
+ 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
- /** Resolve body controls from the configured Rust profile/model; no scene traversal. */
703
- getBodyControls(): BodyControlDescriptor[];
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 declare function getBodyControls(profile: Profile, model?: Object3D): BodyControlDescriptor[];
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;
@@ -2874,11 +2806,14 @@ export interface AIExpressionSnippetMetadata {
2874
2806
  }
2875
2807
 
2876
2808
  export interface Snippet {
2877
- semanticAnimation?: SemanticAnimation;
2878
2809
  name?: string;
2879
2810
  au?: Array<{ id: string | number; t?: number; v?: number; time?: number; intensity?: number; inherit?: boolean }>;
2880
2811
  viseme?: Array<{ key: string | number; t?: number; v?: number; time?: number; intensity?: number; inherit?: boolean }>;
2881
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>;
2882
2817
  channels?: PolymerSnippetChannel[];
2883
2818
  isPlaying?: boolean;
2884
2819
  loop?: boolean;