loomlarge 0.1.0 → 0.1.6

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/dist/index.cjs CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
+ var three = require('three');
6
+
5
7
  var __defProp = Object.defineProperty;
6
8
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
7
9
  var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
@@ -358,6 +360,107 @@ var BONE_AU_TO_BINDINGS = {
358
360
  { node: "TONGUE", channel: "rx", scale: 1, maxDegrees: 20 }
359
361
  ]
360
362
  };
363
+ var isMixedAU = (id) => !!(AU_TO_MORPHS[id]?.length && BONE_AU_TO_BINDINGS[id]?.length);
364
+ var hasLeftRightMorphs = (auId) => {
365
+ const keys = AU_TO_MORPHS[auId] || [];
366
+ return keys.some((k) => /_L$|_R$| L$| R$|Left$|Right$/i.test(k));
367
+ };
368
+ var COMPOSITE_ROTATIONS = [
369
+ {
370
+ node: "JAW",
371
+ pitch: { aus: [25, 26, 27], axis: "rz" },
372
+ // Jaw drop (opens mouth downward)
373
+ yaw: { aus: [30, 35], axis: "ry", negative: 30, positive: 35 },
374
+ // Jaw lateral (left/right)
375
+ roll: null
376
+ // Jaw doesn't have roll
377
+ },
378
+ {
379
+ node: "HEAD",
380
+ pitch: { aus: [54, 53], axis: "rx", negative: 54, positive: 53 },
381
+ // Head down/up
382
+ yaw: { aus: [51, 52], axis: "ry", negative: 51, positive: 52 },
383
+ // Head turn left/right
384
+ roll: { aus: [55, 56], axis: "rz", negative: 55, positive: 56 }
385
+ // Head tilt left/right
386
+ },
387
+ {
388
+ node: "EYE_L",
389
+ pitch: { aus: [64, 63], axis: "rx", negative: 64, positive: 63 },
390
+ // Eyes down/up
391
+ yaw: { aus: [61, 62], axis: "rz", negative: 61, positive: 62 },
392
+ // Eyes left/right (rz for CC4)
393
+ roll: null
394
+ // Eyes don't have roll
395
+ },
396
+ {
397
+ node: "EYE_R",
398
+ pitch: { aus: [64, 63], axis: "rx", negative: 64, positive: 63 },
399
+ // Eyes down/up
400
+ yaw: { aus: [61, 62], axis: "rz", negative: 61, positive: 62 },
401
+ // Eyes left/right (rz for CC4)
402
+ roll: null
403
+ // Eyes don't have roll
404
+ },
405
+ {
406
+ node: "TONGUE",
407
+ pitch: { aus: [38, 37], axis: "rz", negative: 38, positive: 37 },
408
+ // Tongue down/up
409
+ yaw: { aus: [39, 40], axis: "ry", negative: 39, positive: 40 },
410
+ // Tongue left/right
411
+ roll: { aus: [41, 42], axis: "rx", negative: 41, positive: 42 }
412
+ // Tongue tilt left/right
413
+ }
414
+ ];
415
+ var CONTINUUM_PAIRS_MAP = {
416
+ // Eyes horizontal (yaw) - both eyes share same AUs
417
+ 61: { pairId: 62, isNegative: true, axis: "yaw", node: "EYE_L" },
418
+ 62: { pairId: 61, isNegative: false, axis: "yaw", node: "EYE_L" },
419
+ // Eyes vertical (pitch)
420
+ 64: { pairId: 63, isNegative: true, axis: "pitch", node: "EYE_L" },
421
+ 63: { pairId: 64, isNegative: false, axis: "pitch", node: "EYE_L" },
422
+ // Head yaw (turn left/right)
423
+ 51: { pairId: 52, isNegative: true, axis: "yaw", node: "HEAD" },
424
+ 52: { pairId: 51, isNegative: false, axis: "yaw", node: "HEAD" },
425
+ // Head pitch (up/down)
426
+ 54: { pairId: 53, isNegative: true, axis: "pitch", node: "HEAD" },
427
+ 53: { pairId: 54, isNegative: false, axis: "pitch", node: "HEAD" },
428
+ // Head roll (tilt left/right)
429
+ 55: { pairId: 56, isNegative: true, axis: "roll", node: "HEAD" },
430
+ 56: { pairId: 55, isNegative: false, axis: "roll", node: "HEAD" },
431
+ // Jaw yaw (left/right)
432
+ 30: { pairId: 35, isNegative: true, axis: "yaw", node: "JAW" },
433
+ 35: { pairId: 30, isNegative: false, axis: "yaw", node: "JAW" },
434
+ // Tongue yaw (left/right)
435
+ 39: { pairId: 40, isNegative: true, axis: "yaw", node: "TONGUE" },
436
+ 40: { pairId: 39, isNegative: false, axis: "yaw", node: "TONGUE" },
437
+ // Tongue pitch (up/down)
438
+ 38: { pairId: 37, isNegative: true, axis: "pitch", node: "TONGUE" },
439
+ 37: { pairId: 38, isNegative: false, axis: "pitch", node: "TONGUE" },
440
+ // Tongue roll (tilt left/right)
441
+ 41: { pairId: 42, isNegative: true, axis: "roll", node: "TONGUE" },
442
+ 42: { pairId: 41, isNegative: false, axis: "roll", node: "TONGUE" },
443
+ // Extended tongue morphs (continuum pairs)
444
+ 73: { pairId: 74, isNegative: true, axis: "yaw", node: "TONGUE" },
445
+ // Tongue Narrow/Wide
446
+ 74: { pairId: 73, isNegative: false, axis: "yaw", node: "TONGUE" },
447
+ 76: { pairId: 77, isNegative: false, axis: "pitch", node: "TONGUE" },
448
+ // Tongue Tip Up/Down
449
+ 77: { pairId: 76, isNegative: true, axis: "pitch", node: "TONGUE" }
450
+ };
451
+ var CONTINUUM_LABELS = {
452
+ "61-62": "Eyes \u2014 Horizontal",
453
+ "64-63": "Eyes \u2014 Vertical",
454
+ "51-52": "Head \u2014 Horizontal",
455
+ "54-53": "Head \u2014 Vertical",
456
+ "55-56": "Head \u2014 Tilt",
457
+ "30-35": "Jaw \u2014 Horizontal",
458
+ "38-37": "Tongue \u2014 Vertical",
459
+ "39-40": "Tongue \u2014 Horizontal",
460
+ "41-42": "Tongue \u2014 Tilt",
461
+ "73-74": "Tongue \u2014 Width",
462
+ "76-77": "Tongue Tip \u2014 Vertical"
463
+ };
361
464
  var CC4_BONE_NODES = {
362
465
  EYE_L: "CC_Base_L_Eye",
363
466
  EYE_R: "CC_Base_R_Eye",
@@ -490,6 +593,41 @@ var AU_MIX_DEFAULTS = {
490
593
  35: 0.5
491
594
  // jaw left/right
492
595
  };
596
+ var CC4_MESHES = {
597
+ // Body (6 meshes, 80 morphs each) - default render order 0
598
+ "CC_Base_Body_1": { category: "body", morphCount: 80 },
599
+ "CC_Base_Body_2": { category: "body", morphCount: 80 },
600
+ "CC_Base_Body_3": { category: "body", morphCount: 80 },
601
+ "CC_Base_Body_4": { category: "body", morphCount: 80 },
602
+ "CC_Base_Body_5": { category: "body", morphCount: 80 },
603
+ "CC_Base_Body_6": { category: "body", morphCount: 80 },
604
+ // Eyes (bone-driven, no morphs) - render first (behind everything)
605
+ "CC_Base_Eye": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
606
+ "CC_Base_Eye_1": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
607
+ "CC_Base_Eye_2": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
608
+ "CC_Base_Eye_3": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
609
+ "CC_Base_Eye_4": { category: "eye", morphCount: 0, material: { renderOrder: -10 } },
610
+ // Eye occlusion (94 morphs each) - render on top of eyes with transparency support
611
+ "CC_Base_EyeOcclusion_1": { category: "eyeOcclusion", morphCount: 94, material: { renderOrder: 2, transparent: true, opacity: 1, depthWrite: true, depthTest: true, blending: "Normal" } },
612
+ "CC_Base_EyeOcclusion_2": { category: "eyeOcclusion", morphCount: 94, material: { renderOrder: 2, transparent: true, opacity: 1, depthWrite: true, depthTest: true, blending: "Normal" } },
613
+ // Tear lines (90 morphs each) - on top of eyes/face
614
+ "CC_Base_TearLine_1": { category: "tearLine", morphCount: 90, material: { renderOrder: 2 } },
615
+ "CC_Base_TearLine_2": { category: "tearLine", morphCount: 90, material: { renderOrder: 2 } },
616
+ // Cornea (no morphs) - render first with eyes
617
+ "CC_Base_Cornea": { category: "cornea", morphCount: 0, material: { renderOrder: -10 } },
618
+ "CC_Base_Cornea_1": { category: "cornea", morphCount: 0, material: { renderOrder: -10 } },
619
+ // Teeth (no morphs, follow jaw bone) - default render order
620
+ "CC_Base_Teeth_1": { category: "teeth", morphCount: 0 },
621
+ "CC_Base_Teeth_2": { category: "teeth", morphCount: 0 },
622
+ // Tongue (23 morphs) - default render order
623
+ "CC_Base_Tongue": { category: "tongue", morphCount: 23 },
624
+ // Eyebrows (91 morphs each) - above face
625
+ "Male_Bushy_1": { category: "eyebrow", morphCount: 91, material: { renderOrder: 5 } },
626
+ "Male_Bushy_2": { category: "eyebrow", morphCount: 91, material: { renderOrder: 5 } },
627
+ // Hair (14 styling morphs each) - render last (on top of everything)
628
+ "Side_part_wavy_1": { category: "hair", morphCount: 14, material: { renderOrder: 10 } },
629
+ "Side_part_wavy_2": { category: "hair", morphCount: 14, material: { renderOrder: 10 } }
630
+ };
493
631
  var MORPH_TO_MESH = {
494
632
  // Face/AU morphs affect the main face mesh and both eyebrow meshes.
495
633
  face: ["CC_Base_Body_1", "Male_Bushy_1", "Male_Bushy_2"],
@@ -541,6 +679,10 @@ var _LoomLargeThree = class _LoomLargeThree {
541
679
  __publicField(this, "mixWeights", {});
542
680
  // Viseme state
543
681
  __publicField(this, "visemeValues", new Array(15).fill(0));
682
+ // Internal RAF loop
683
+ __publicField(this, "clock", new three.Clock());
684
+ __publicField(this, "rafId", null);
685
+ __publicField(this, "running", false);
544
686
  this.config = config.auMappings || CC4_PRESET;
545
687
  this.mixWeights = { ...this.config.auMixDefaults };
546
688
  this.animation = animation || new AnimationThree();
@@ -584,7 +726,30 @@ var _LoomLargeThree = class _LoomLargeThree {
584
726
  this.animation.tick(dtSeconds);
585
727
  this.flushPendingComposites();
586
728
  }
729
+ /** Start the internal RAF loop */
730
+ start() {
731
+ if (this.running) return;
732
+ this.running = true;
733
+ this.clock.start();
734
+ const tick = () => {
735
+ if (!this.running) return;
736
+ const dt = this.clock.getDelta();
737
+ this.update(dt);
738
+ this.rafId = requestAnimationFrame(tick);
739
+ };
740
+ this.rafId = requestAnimationFrame(tick);
741
+ }
742
+ /** Stop the internal RAF loop */
743
+ stop() {
744
+ this.running = false;
745
+ if (this.rafId !== null) {
746
+ cancelAnimationFrame(this.rafId);
747
+ this.rafId = null;
748
+ }
749
+ this.clock.stop();
750
+ }
587
751
  dispose() {
752
+ this.stop();
588
753
  this.clearTransitions();
589
754
  this.meshes = [];
590
755
  this.model = null;
@@ -1165,12 +1330,26 @@ var HairPhysics = class {
1165
1330
  }
1166
1331
  };
1167
1332
 
1333
+ exports.AU_INFO = AU_INFO;
1334
+ exports.AU_MIX_DEFAULTS = AU_MIX_DEFAULTS;
1335
+ exports.AU_TO_MORPHS = AU_TO_MORPHS;
1168
1336
  exports.AnimationThree = AnimationThree;
1337
+ exports.BONE_AU_TO_BINDINGS = BONE_AU_TO_BINDINGS;
1338
+ exports.CC4_BONE_NODES = CC4_BONE_NODES;
1339
+ exports.CC4_EYE_MESH_NODES = CC4_EYE_MESH_NODES;
1340
+ exports.CC4_MESHES = CC4_MESHES;
1169
1341
  exports.CC4_PRESET = CC4_PRESET;
1342
+ exports.COMPOSITE_ROTATIONS = COMPOSITE_ROTATIONS;
1343
+ exports.CONTINUUM_LABELS = CONTINUUM_LABELS;
1344
+ exports.CONTINUUM_PAIRS_MAP = CONTINUUM_PAIRS_MAP;
1170
1345
  exports.DEFAULT_HAIR_PHYSICS_CONFIG = DEFAULT_HAIR_PHYSICS_CONFIG;
1171
1346
  exports.HairPhysics = HairPhysics;
1172
1347
  exports.LoomLargeThree = LoomLargeThree;
1348
+ exports.MORPH_TO_MESH = MORPH_TO_MESH;
1349
+ exports.VISEME_KEYS = VISEME_KEYS;
1173
1350
  exports.collectMorphMeshes = collectMorphMeshes;
1174
1351
  exports.default = LoomLargeThree;
1352
+ exports.hasLeftRightMorphs = hasLeftRightMorphs;
1353
+ exports.isMixedAU = isMixedAU;
1175
1354
  //# sourceMappingURL=index.cjs.map
1176
1355
  //# sourceMappingURL=index.cjs.map