@holoscript/engine 6.0.3 → 6.0.4

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 (192) hide show
  1. package/dist/AutoMesher-CK47F6AV.js +17 -0
  2. package/dist/GPUBuffers-2LHBCD7X.js +9 -0
  3. package/dist/WebGPUContext-TNEUYU2Y.js +11 -0
  4. package/dist/animation/index.cjs +38 -38
  5. package/dist/animation/index.d.cts +1 -1
  6. package/dist/animation/index.d.ts +1 -1
  7. package/dist/animation/index.js +1 -1
  8. package/dist/audio/index.cjs +16 -6
  9. package/dist/audio/index.d.cts +1 -1
  10. package/dist/audio/index.d.ts +1 -1
  11. package/dist/audio/index.js +1 -1
  12. package/dist/camera/index.cjs +23 -23
  13. package/dist/camera/index.d.cts +1 -1
  14. package/dist/camera/index.d.ts +1 -1
  15. package/dist/camera/index.js +1 -1
  16. package/dist/character/index.cjs +6 -4
  17. package/dist/character/index.js +1 -1
  18. package/dist/choreography/index.cjs +1194 -0
  19. package/dist/choreography/index.d.cts +687 -0
  20. package/dist/choreography/index.d.ts +687 -0
  21. package/dist/choreography/index.js +1156 -0
  22. package/dist/chunk-2CSNRI2N.js +217 -0
  23. package/dist/chunk-33T2WINR.js +266 -0
  24. package/dist/chunk-35R73OFM.js +1257 -0
  25. package/dist/chunk-4MMDSUNP.js +1256 -0
  26. package/dist/chunk-5V6HOU72.js +319 -0
  27. package/dist/chunk-6QOP6PYF.js +1038 -0
  28. package/dist/chunk-7KMJVHIL.js +8944 -0
  29. package/dist/chunk-7VPUC62U.js +1106 -0
  30. package/dist/chunk-A2Y6RCAT.js +1878 -0
  31. package/dist/chunk-AHM42MK6.js +8944 -0
  32. package/dist/chunk-BL7IDTHE.js +218 -0
  33. package/dist/chunk-CITOMSWL.js +10462 -0
  34. package/dist/chunk-CXDPKW2K.js +8944 -0
  35. package/dist/chunk-CXZPLD4S.js +223 -0
  36. package/dist/chunk-CZYJE7IH.js +5169 -0
  37. package/dist/chunk-D2OP7YC7.js +6325 -0
  38. package/dist/chunk-EDRVQHUU.js +1544 -0
  39. package/dist/chunk-EJSLOOW2.js +3589 -0
  40. package/dist/chunk-F53SFGW5.js +1878 -0
  41. package/dist/chunk-HCFPELPY.js +919 -0
  42. package/dist/chunk-HNEE36PY.js +93 -0
  43. package/dist/chunk-HYXNV36F.js +1256 -0
  44. package/dist/chunk-IB7KHVFY.js +821 -0
  45. package/dist/chunk-IBBO7YYG.js +690 -0
  46. package/dist/chunk-ILIBGINU.js +5470 -0
  47. package/dist/chunk-IS4MHLKN.js +5479 -0
  48. package/dist/chunk-JT2PFKWD.js +5479 -0
  49. package/dist/chunk-K4CUB4NY.js +1038 -0
  50. package/dist/chunk-KATDQXRJ.js +10462 -0
  51. package/dist/chunk-KBQE6ZFJ.js +8944 -0
  52. package/dist/chunk-KBVD5K7E.js +560 -0
  53. package/dist/chunk-KCDPVQRY.js +4088 -0
  54. package/dist/chunk-KN4QJPKN.js +8944 -0
  55. package/dist/chunk-KWJ3ROSI.js +8944 -0
  56. package/dist/chunk-L45VF6DD.js +919 -0
  57. package/dist/chunk-LY4T37YK.js +307 -0
  58. package/dist/chunk-MDN5WZXA.js +1544 -0
  59. package/dist/chunk-MGCDP6VU.js +928 -0
  60. package/dist/chunk-NCX7X6G2.js +8681 -0
  61. package/dist/chunk-OF54BPVD.js +913 -0
  62. package/dist/chunk-OWSN2Q3Q.js +690 -0
  63. package/dist/chunk-PRRB5TTA.js +406 -0
  64. package/dist/chunk-PXWVQF76.js +4086 -0
  65. package/dist/chunk-PYCOIDT2.js +812 -0
  66. package/dist/chunk-PZCSADOV.js +928 -0
  67. package/dist/chunk-Q2XBVS2K.js +1038 -0
  68. package/dist/chunk-QDZRXWN5.js +1776 -0
  69. package/dist/chunk-RNWOZ6WQ.js +913 -0
  70. package/dist/chunk-ROLFT4CJ.js +1693 -0
  71. package/dist/chunk-SLTJRZ2N.js +266 -0
  72. package/dist/chunk-SRUS5XSU.js +4088 -0
  73. package/dist/chunk-TKCA3WZ5.js +5409 -0
  74. package/dist/chunk-TNRMXYI2.js +1650 -0
  75. package/dist/chunk-TQB3GJGM.js +9763 -0
  76. package/dist/chunk-TUFGXG6K.js +510 -0
  77. package/dist/chunk-U6KMTGQJ.js +632 -0
  78. package/dist/chunk-VMGJQST6.js +8681 -0
  79. package/dist/chunk-X4F4TCG4.js +5470 -0
  80. package/dist/chunk-ZIFROE75.js +1544 -0
  81. package/dist/chunk-ZIJQYHSQ.js +1204 -0
  82. package/dist/combat/index.cjs +4 -4
  83. package/dist/combat/index.d.cts +1 -1
  84. package/dist/combat/index.d.ts +1 -1
  85. package/dist/combat/index.js +1 -1
  86. package/dist/ecs/index.cjs +1 -1
  87. package/dist/ecs/index.js +1 -1
  88. package/dist/environment/index.cjs +14 -14
  89. package/dist/environment/index.d.cts +1 -1
  90. package/dist/environment/index.d.ts +1 -1
  91. package/dist/environment/index.js +1 -1
  92. package/dist/gpu/index.cjs +4810 -0
  93. package/dist/gpu/index.js +3714 -0
  94. package/dist/hologram/index.cjs +27 -1
  95. package/dist/hologram/index.js +1 -1
  96. package/dist/index-B2PIsAmR.d.cts +2180 -0
  97. package/dist/index-B2PIsAmR.d.ts +2180 -0
  98. package/dist/index-BHySEPX7.d.cts +2921 -0
  99. package/dist/index-BJV21zuy.d.cts +341 -0
  100. package/dist/index-BJV21zuy.d.ts +341 -0
  101. package/dist/index-BQutTphC.d.cts +790 -0
  102. package/dist/index-ByIq2XrS.d.cts +3910 -0
  103. package/dist/index-BysHjDSO.d.cts +224 -0
  104. package/dist/index-BysHjDSO.d.ts +224 -0
  105. package/dist/index-CKwAJGck.d.ts +455 -0
  106. package/dist/index-CUl3QstQ.d.cts +3006 -0
  107. package/dist/index-CUl3QstQ.d.ts +3006 -0
  108. package/dist/index-CmYtNiI-.d.cts +953 -0
  109. package/dist/index-CmYtNiI-.d.ts +953 -0
  110. package/dist/index-CnRzWxi_.d.cts +522 -0
  111. package/dist/index-CnRzWxi_.d.ts +522 -0
  112. package/dist/index-CwRWbSC7.d.ts +2921 -0
  113. package/dist/index-CxKIBstO.d.ts +790 -0
  114. package/dist/index-DJ6-R8vh.d.cts +455 -0
  115. package/dist/index-DQKisbcI.d.cts +4968 -0
  116. package/dist/index-DQKisbcI.d.ts +4968 -0
  117. package/dist/index-DRT2zJez.d.ts +3910 -0
  118. package/dist/index-DfNLiAka.d.cts +192 -0
  119. package/dist/index-DfNLiAka.d.ts +192 -0
  120. package/dist/index-nMvkoRm8.d.cts +405 -0
  121. package/dist/index-nMvkoRm8.d.ts +405 -0
  122. package/dist/index-s9yOFU37.d.cts +604 -0
  123. package/dist/index-s9yOFU37.d.ts +604 -0
  124. package/dist/index.cjs +22966 -6960
  125. package/dist/index.d.cts +864 -20
  126. package/dist/index.d.ts +864 -20
  127. package/dist/index.js +3062 -48
  128. package/dist/input/index.cjs +1 -1
  129. package/dist/input/index.js +1 -1
  130. package/dist/orbital/index.cjs +3 -3
  131. package/dist/orbital/index.d.cts +1 -1
  132. package/dist/orbital/index.d.ts +1 -1
  133. package/dist/orbital/index.js +1 -1
  134. package/dist/particles/index.cjs +16 -16
  135. package/dist/particles/index.d.cts +1 -1
  136. package/dist/particles/index.d.ts +1 -1
  137. package/dist/particles/index.js +1 -1
  138. package/dist/physics/index.cjs +2377 -21
  139. package/dist/physics/index.d.cts +1 -1
  140. package/dist/physics/index.d.ts +1 -1
  141. package/dist/physics/index.js +35 -1
  142. package/dist/postfx/index.cjs +3491 -0
  143. package/dist/postfx/index.js +93 -0
  144. package/dist/procedural/index.cjs +1 -1
  145. package/dist/procedural/index.js +1 -1
  146. package/dist/puppeteer-5VF6KDVO.js +52197 -0
  147. package/dist/puppeteer-IZVZ3SG4.js +52197 -0
  148. package/dist/rendering/index.cjs +33 -32
  149. package/dist/rendering/index.d.cts +1 -1
  150. package/dist/rendering/index.d.ts +1 -1
  151. package/dist/rendering/index.js +8 -6
  152. package/dist/runtime/index.cjs +23 -13
  153. package/dist/runtime/index.d.cts +1 -1
  154. package/dist/runtime/index.d.ts +1 -1
  155. package/dist/runtime/index.js +8 -6
  156. package/dist/runtime/protocols/index.cjs +349 -0
  157. package/dist/runtime/protocols/index.js +15 -0
  158. package/dist/scene/index.cjs +8 -8
  159. package/dist/scene/index.d.cts +1 -1
  160. package/dist/scene/index.d.ts +1 -1
  161. package/dist/scene/index.js +1 -1
  162. package/dist/shader/index.cjs +3087 -0
  163. package/dist/shader/index.js +3044 -0
  164. package/dist/simulation/index.cjs +10680 -0
  165. package/dist/simulation/index.d.cts +3 -0
  166. package/dist/simulation/index.d.ts +3 -0
  167. package/dist/simulation/index.js +307 -0
  168. package/dist/spatial/index.cjs +2443 -0
  169. package/dist/spatial/index.d.cts +1545 -0
  170. package/dist/spatial/index.d.ts +1545 -0
  171. package/dist/spatial/index.js +2400 -0
  172. package/dist/terrain/index.cjs +1 -1
  173. package/dist/terrain/index.d.cts +1 -1
  174. package/dist/terrain/index.d.ts +1 -1
  175. package/dist/terrain/index.js +1 -1
  176. package/dist/transformers.node-4NKAPD5U.js +45620 -0
  177. package/dist/vm/index.cjs +7 -8
  178. package/dist/vm/index.d.cts +1 -1
  179. package/dist/vm/index.d.ts +1 -1
  180. package/dist/vm/index.js +1 -1
  181. package/dist/vm-bridge/index.cjs +2 -2
  182. package/dist/vm-bridge/index.d.cts +2 -2
  183. package/dist/vm-bridge/index.d.ts +2 -2
  184. package/dist/vm-bridge/index.js +1 -1
  185. package/dist/vr/index.cjs +6 -6
  186. package/dist/vr/index.js +1 -1
  187. package/dist/world/index.cjs +3 -3
  188. package/dist/world/index.d.cts +1 -1
  189. package/dist/world/index.d.ts +1 -1
  190. package/dist/world/index.js +1 -1
  191. package/package.json +53 -21
  192. package/LICENSE +0 -21
@@ -0,0 +1,1204 @@
1
+ import {
2
+ __export
3
+ } from "./chunk-AKLW2MUS.js";
4
+
5
+ // src/character/index.ts
6
+ var character_exports = {};
7
+ __export(character_exports, {
8
+ DEFAULT_LIP_SYNC_CONFIG: () => DEFAULT_LIP_SYNC_CONFIG,
9
+ EXPRESSION_PRESETS: () => EXPRESSION_PRESETS,
10
+ FACS_ACTION_UNITS: () => FACS_ACTION_UNITS,
11
+ HUMANOID_65_SKELETON: () => HUMANOID_65_SKELETON,
12
+ HUMANOID_BONE_NAMES: () => HUMANOID_BONE_NAMES,
13
+ IdleBehaviorSystem: () => IdleBehaviorSystem,
14
+ LipSyncEngine: () => LipSyncEngine,
15
+ MIXAMO_BONE_MAP: () => MIXAMO_BONE_MAP,
16
+ PIPELINE_STAGES: () => PIPELINE_STAGES,
17
+ VISEME_15: () => VISEME_15,
18
+ VRM_BONE_MAP: () => VRM_BONE_MAP,
19
+ applyMorphTargets: () => applyMorphTargets,
20
+ computeSparseMorphTarget: () => computeSparseMorphTarget,
21
+ createIdleBehaviorSystem: () => createIdleBehaviorSystem,
22
+ evaluateExpression: () => evaluateExpression,
23
+ getActionUnit: () => getActionUnit,
24
+ getBoneChain: () => getBoneChain,
25
+ getBoneChildren: () => getBoneChildren,
26
+ getViseme: () => getViseme,
27
+ validateSkeleton: () => validateSkeleton
28
+ });
29
+
30
+ // src/character/CharacterPipelineTypes.ts
31
+ var PIPELINE_STAGES = [
32
+ "sculpt",
33
+ "mesh_extraction",
34
+ "optimization",
35
+ "rigging",
36
+ "facial",
37
+ "dressing",
38
+ "deployment"
39
+ ];
40
+
41
+ // src/character/HumanoidSkeleton.ts
42
+ var HUMANOID_BONE_NAMES = [
43
+ // Root
44
+ "root",
45
+ "hips",
46
+ // Spine chain (5)
47
+ "spine",
48
+ "spine1",
49
+ "spine2",
50
+ "neck",
51
+ "head",
52
+ // Left arm (4 + 15 fingers = 19)
53
+ "left_shoulder",
54
+ "left_upper_arm",
55
+ "left_forearm",
56
+ "left_hand",
57
+ "left_thumb_proximal",
58
+ "left_thumb_intermediate",
59
+ "left_thumb_distal",
60
+ "left_index_proximal",
61
+ "left_index_intermediate",
62
+ "left_index_distal",
63
+ "left_middle_proximal",
64
+ "left_middle_intermediate",
65
+ "left_middle_distal",
66
+ "left_ring_proximal",
67
+ "left_ring_intermediate",
68
+ "left_ring_distal",
69
+ "left_pinky_proximal",
70
+ "left_pinky_intermediate",
71
+ "left_pinky_distal",
72
+ // Right arm (4 + 15 fingers = 19)
73
+ "right_shoulder",
74
+ "right_upper_arm",
75
+ "right_forearm",
76
+ "right_hand",
77
+ "right_thumb_proximal",
78
+ "right_thumb_intermediate",
79
+ "right_thumb_distal",
80
+ "right_index_proximal",
81
+ "right_index_intermediate",
82
+ "right_index_distal",
83
+ "right_middle_proximal",
84
+ "right_middle_intermediate",
85
+ "right_middle_distal",
86
+ "right_ring_proximal",
87
+ "right_ring_intermediate",
88
+ "right_ring_distal",
89
+ "right_pinky_proximal",
90
+ "right_pinky_intermediate",
91
+ "right_pinky_distal",
92
+ // Left leg (5)
93
+ "left_upper_leg",
94
+ "left_lower_leg",
95
+ "left_foot",
96
+ "left_toes",
97
+ "left_toe_end",
98
+ // Right leg (5)
99
+ "right_upper_leg",
100
+ "right_lower_leg",
101
+ "right_foot",
102
+ "right_toes",
103
+ "right_toe_end"
104
+ ];
105
+ var HUMANOID_65_SKELETON = [
106
+ // Root & hips
107
+ { name: "root", parent: null, position: [0, 0, 0], length: 0 },
108
+ {
109
+ name: "hips",
110
+ parent: "root",
111
+ position: [0, 0.95, 0],
112
+ length: 0.12,
113
+ rotationLimits: [-30, 30, -40, 40, -30, 30]
114
+ },
115
+ // Spine chain
116
+ {
117
+ name: "spine",
118
+ parent: "hips",
119
+ position: [0, 0.12, 0],
120
+ length: 0.12,
121
+ rotationLimits: [-20, 40, -20, 20, -20, 20]
122
+ },
123
+ {
124
+ name: "spine1",
125
+ parent: "spine",
126
+ position: [0, 0.12, 0],
127
+ length: 0.12,
128
+ rotationLimits: [-20, 30, -15, 15, -15, 15]
129
+ },
130
+ {
131
+ name: "spine2",
132
+ parent: "spine1",
133
+ position: [0, 0.12, 0],
134
+ length: 0.12,
135
+ rotationLimits: [-15, 25, -10, 10, -10, 10]
136
+ },
137
+ {
138
+ name: "neck",
139
+ parent: "spine2",
140
+ position: [0, 0.12, 0],
141
+ length: 0.08,
142
+ rotationLimits: [-40, 40, -50, 50, -30, 30]
143
+ },
144
+ {
145
+ name: "head",
146
+ parent: "neck",
147
+ position: [0, 0.08, 0],
148
+ length: 0.2,
149
+ rotationLimits: [-30, 30, -60, 60, -20, 20]
150
+ },
151
+ // Left arm
152
+ {
153
+ name: "left_shoulder",
154
+ parent: "spine2",
155
+ position: [0.08, 0.1, 0],
156
+ length: 0.1,
157
+ rotationLimits: [-15, 15, -10, 30, -30, 10]
158
+ },
159
+ {
160
+ name: "left_upper_arm",
161
+ parent: "left_shoulder",
162
+ position: [0.1, 0, 0],
163
+ length: 0.28,
164
+ rotationLimits: [-90, 90, -60, 135, -90, 30]
165
+ },
166
+ {
167
+ name: "left_forearm",
168
+ parent: "left_upper_arm",
169
+ position: [0.28, 0, 0],
170
+ length: 0.25,
171
+ rotationLimits: [0, 145, -90, 90, 0, 0]
172
+ },
173
+ {
174
+ name: "left_hand",
175
+ parent: "left_forearm",
176
+ position: [0.25, 0, 0],
177
+ length: 0.08,
178
+ rotationLimits: [-70, 70, -30, 30, -15, 15]
179
+ },
180
+ // Left fingers — thumb
181
+ { name: "left_thumb_proximal", parent: "left_hand", position: [0.03, -0.01, 0.02], length: 0.03 },
182
+ {
183
+ name: "left_thumb_intermediate",
184
+ parent: "left_thumb_proximal",
185
+ position: [0.03, 0, 0],
186
+ length: 0.025
187
+ },
188
+ {
189
+ name: "left_thumb_distal",
190
+ parent: "left_thumb_intermediate",
191
+ position: [0.025, 0, 0],
192
+ length: 0.02
193
+ },
194
+ // Left fingers — index
195
+ { name: "left_index_proximal", parent: "left_hand", position: [0.08, 0, 0.02], length: 0.035 },
196
+ {
197
+ name: "left_index_intermediate",
198
+ parent: "left_index_proximal",
199
+ position: [0.035, 0, 0],
200
+ length: 0.025
201
+ },
202
+ {
203
+ name: "left_index_distal",
204
+ parent: "left_index_intermediate",
205
+ position: [0.025, 0, 0],
206
+ length: 0.02
207
+ },
208
+ // Left fingers — middle
209
+ { name: "left_middle_proximal", parent: "left_hand", position: [0.08, 0, 0], length: 0.038 },
210
+ {
211
+ name: "left_middle_intermediate",
212
+ parent: "left_middle_proximal",
213
+ position: [0.038, 0, 0],
214
+ length: 0.028
215
+ },
216
+ {
217
+ name: "left_middle_distal",
218
+ parent: "left_middle_intermediate",
219
+ position: [0.028, 0, 0],
220
+ length: 0.02
221
+ },
222
+ // Left fingers — ring
223
+ { name: "left_ring_proximal", parent: "left_hand", position: [0.08, 0, -0.015], length: 0.035 },
224
+ {
225
+ name: "left_ring_intermediate",
226
+ parent: "left_ring_proximal",
227
+ position: [0.035, 0, 0],
228
+ length: 0.025
229
+ },
230
+ {
231
+ name: "left_ring_distal",
232
+ parent: "left_ring_intermediate",
233
+ position: [0.025, 0, 0],
234
+ length: 0.018
235
+ },
236
+ // Left fingers — pinky
237
+ { name: "left_pinky_proximal", parent: "left_hand", position: [0.075, 0, -0.03], length: 0.028 },
238
+ {
239
+ name: "left_pinky_intermediate",
240
+ parent: "left_pinky_proximal",
241
+ position: [0.028, 0, 0],
242
+ length: 0.02
243
+ },
244
+ {
245
+ name: "left_pinky_distal",
246
+ parent: "left_pinky_intermediate",
247
+ position: [0.02, 0, 0],
248
+ length: 0.015
249
+ },
250
+ // Right arm (mirrored X)
251
+ {
252
+ name: "right_shoulder",
253
+ parent: "spine2",
254
+ position: [-0.08, 0.1, 0],
255
+ length: 0.1,
256
+ rotationLimits: [-15, 15, -30, 10, -10, 30]
257
+ },
258
+ {
259
+ name: "right_upper_arm",
260
+ parent: "right_shoulder",
261
+ position: [-0.1, 0, 0],
262
+ length: 0.28,
263
+ rotationLimits: [-90, 90, -135, 60, -30, 90]
264
+ },
265
+ {
266
+ name: "right_forearm",
267
+ parent: "right_upper_arm",
268
+ position: [-0.28, 0, 0],
269
+ length: 0.25,
270
+ rotationLimits: [0, 145, -90, 90, 0, 0]
271
+ },
272
+ {
273
+ name: "right_hand",
274
+ parent: "right_forearm",
275
+ position: [-0.25, 0, 0],
276
+ length: 0.08,
277
+ rotationLimits: [-70, 70, -30, 30, -15, 15]
278
+ },
279
+ // Right fingers — thumb
280
+ {
281
+ name: "right_thumb_proximal",
282
+ parent: "right_hand",
283
+ position: [-0.03, -0.01, 0.02],
284
+ length: 0.03
285
+ },
286
+ {
287
+ name: "right_thumb_intermediate",
288
+ parent: "right_thumb_proximal",
289
+ position: [-0.03, 0, 0],
290
+ length: 0.025
291
+ },
292
+ {
293
+ name: "right_thumb_distal",
294
+ parent: "right_thumb_intermediate",
295
+ position: [-0.025, 0, 0],
296
+ length: 0.02
297
+ },
298
+ // Right fingers — index
299
+ { name: "right_index_proximal", parent: "right_hand", position: [-0.08, 0, 0.02], length: 0.035 },
300
+ {
301
+ name: "right_index_intermediate",
302
+ parent: "right_index_proximal",
303
+ position: [-0.035, 0, 0],
304
+ length: 0.025
305
+ },
306
+ {
307
+ name: "right_index_distal",
308
+ parent: "right_index_intermediate",
309
+ position: [-0.025, 0, 0],
310
+ length: 0.02
311
+ },
312
+ // Right fingers — middle
313
+ { name: "right_middle_proximal", parent: "right_hand", position: [-0.08, 0, 0], length: 0.038 },
314
+ {
315
+ name: "right_middle_intermediate",
316
+ parent: "right_middle_proximal",
317
+ position: [-0.038, 0, 0],
318
+ length: 0.028
319
+ },
320
+ {
321
+ name: "right_middle_distal",
322
+ parent: "right_middle_intermediate",
323
+ position: [-0.028, 0, 0],
324
+ length: 0.02
325
+ },
326
+ // Right fingers — ring
327
+ {
328
+ name: "right_ring_proximal",
329
+ parent: "right_hand",
330
+ position: [-0.08, 0, -0.015],
331
+ length: 0.035
332
+ },
333
+ {
334
+ name: "right_ring_intermediate",
335
+ parent: "right_ring_proximal",
336
+ position: [-0.035, 0, 0],
337
+ length: 0.025
338
+ },
339
+ {
340
+ name: "right_ring_distal",
341
+ parent: "right_ring_intermediate",
342
+ position: [-0.025, 0, 0],
343
+ length: 0.018
344
+ },
345
+ // Right fingers — pinky
346
+ {
347
+ name: "right_pinky_proximal",
348
+ parent: "right_hand",
349
+ position: [-0.075, 0, -0.03],
350
+ length: 0.028
351
+ },
352
+ {
353
+ name: "right_pinky_intermediate",
354
+ parent: "right_pinky_proximal",
355
+ position: [-0.028, 0, 0],
356
+ length: 0.02
357
+ },
358
+ {
359
+ name: "right_pinky_distal",
360
+ parent: "right_pinky_intermediate",
361
+ position: [-0.02, 0, 0],
362
+ length: 0.015
363
+ },
364
+ // Left leg
365
+ {
366
+ name: "left_upper_leg",
367
+ parent: "hips",
368
+ position: [0.09, -0.05, 0],
369
+ length: 0.42,
370
+ rotationLimits: [-20, 120, -45, 45, -40, 30]
371
+ },
372
+ {
373
+ name: "left_lower_leg",
374
+ parent: "left_upper_leg",
375
+ position: [0, -0.42, 0],
376
+ length: 0.4,
377
+ rotationLimits: [-130, 0, 0, 0, 0, 0]
378
+ },
379
+ {
380
+ name: "left_foot",
381
+ parent: "left_lower_leg",
382
+ position: [0, -0.4, 0],
383
+ length: 0.15,
384
+ rotationLimits: [-40, 40, -20, 20, -15, 15]
385
+ },
386
+ {
387
+ name: "left_toes",
388
+ parent: "left_foot",
389
+ position: [0, 0, 0.15],
390
+ length: 0.06,
391
+ rotationLimits: [-30, 60, 0, 0, 0, 0]
392
+ },
393
+ { name: "left_toe_end", parent: "left_toes", position: [0, 0, 0.06], length: 0 },
394
+ // Right leg (mirrored X)
395
+ {
396
+ name: "right_upper_leg",
397
+ parent: "hips",
398
+ position: [-0.09, -0.05, 0],
399
+ length: 0.42,
400
+ rotationLimits: [-20, 120, -45, 45, -30, 40]
401
+ },
402
+ {
403
+ name: "right_lower_leg",
404
+ parent: "right_upper_leg",
405
+ position: [0, -0.42, 0],
406
+ length: 0.4,
407
+ rotationLimits: [-130, 0, 0, 0, 0, 0]
408
+ },
409
+ {
410
+ name: "right_foot",
411
+ parent: "right_lower_leg",
412
+ position: [0, -0.4, 0],
413
+ length: 0.15,
414
+ rotationLimits: [-40, 40, -20, 20, -15, 15]
415
+ },
416
+ {
417
+ name: "right_toes",
418
+ parent: "right_foot",
419
+ position: [0, 0, 0.15],
420
+ length: 0.06,
421
+ rotationLimits: [-30, 60, 0, 0, 0, 0]
422
+ },
423
+ { name: "right_toe_end", parent: "right_toes", position: [0, 0, 0.06], length: 0 }
424
+ ];
425
+ var MIXAMO_BONE_MAP = {
426
+ hips: "mixamorig:Hips",
427
+ spine: "mixamorig:Spine",
428
+ spine1: "mixamorig:Spine1",
429
+ spine2: "mixamorig:Spine2",
430
+ neck: "mixamorig:Neck",
431
+ head: "mixamorig:Head",
432
+ left_shoulder: "mixamorig:LeftShoulder",
433
+ left_upper_arm: "mixamorig:LeftArm",
434
+ left_forearm: "mixamorig:LeftForeArm",
435
+ left_hand: "mixamorig:LeftHand",
436
+ right_shoulder: "mixamorig:RightShoulder",
437
+ right_upper_arm: "mixamorig:RightArm",
438
+ right_forearm: "mixamorig:RightForeArm",
439
+ right_hand: "mixamorig:RightHand",
440
+ left_upper_leg: "mixamorig:LeftUpLeg",
441
+ left_lower_leg: "mixamorig:LeftLeg",
442
+ left_foot: "mixamorig:LeftFoot",
443
+ left_toes: "mixamorig:LeftToeBase",
444
+ right_upper_leg: "mixamorig:RightUpLeg",
445
+ right_lower_leg: "mixamorig:RightLeg",
446
+ right_foot: "mixamorig:RightFoot",
447
+ right_toes: "mixamorig:RightToeBase"
448
+ };
449
+ var VRM_BONE_MAP = {
450
+ hips: "hips",
451
+ spine: "spine",
452
+ spine2: "chest",
453
+ neck: "neck",
454
+ head: "head",
455
+ left_shoulder: "leftShoulder",
456
+ left_upper_arm: "leftUpperArm",
457
+ left_forearm: "leftLowerArm",
458
+ left_hand: "leftHand",
459
+ right_shoulder: "rightShoulder",
460
+ right_upper_arm: "rightUpperArm",
461
+ right_forearm: "rightLowerArm",
462
+ right_hand: "rightHand",
463
+ left_upper_leg: "leftUpperLeg",
464
+ left_lower_leg: "leftLowerLeg",
465
+ left_foot: "leftFoot",
466
+ left_toes: "leftToes",
467
+ right_upper_leg: "rightUpperLeg",
468
+ right_lower_leg: "rightLowerLeg",
469
+ right_foot: "rightFoot",
470
+ right_toes: "rightToes"
471
+ };
472
+ function getBoneChildren(boneName, skeleton = HUMANOID_65_SKELETON) {
473
+ return skeleton.filter((b) => b.parent === boneName);
474
+ }
475
+ function getBoneChain(boneName, skeleton = HUMANOID_65_SKELETON) {
476
+ const chain = [];
477
+ let current = skeleton.find((b) => b.name === boneName);
478
+ while (current) {
479
+ chain.unshift(current);
480
+ if (!current.parent) break;
481
+ current = skeleton.find((b) => b.name === current.parent);
482
+ }
483
+ return chain;
484
+ }
485
+ function validateSkeleton(skeleton) {
486
+ const errors = [];
487
+ const names = new Set(skeleton.map((b) => b.name));
488
+ for (const bone of skeleton) {
489
+ if (bone.parent !== null && !names.has(bone.parent)) {
490
+ errors.push(`Bone "${bone.name}" references missing parent "${bone.parent}"`);
491
+ }
492
+ }
493
+ const roots = skeleton.filter((b) => b.parent === null);
494
+ if (roots.length !== 1) {
495
+ errors.push(`Expected exactly 1 root bone, found ${roots.length}`);
496
+ }
497
+ return { valid: errors.length === 0, errors };
498
+ }
499
+
500
+ // src/character/FACSSystem.ts
501
+ var FACS_ACTION_UNITS = [
502
+ // Upper Face — Brow & Forehead
503
+ {
504
+ id: 1,
505
+ name: "Inner Brow Raise",
506
+ region: "brow",
507
+ description: "Frontalis (medial)",
508
+ bilateral: true,
509
+ arkitMapping: ["browInnerUp"]
510
+ },
511
+ {
512
+ id: 2,
513
+ name: "Outer Brow Raise",
514
+ region: "brow",
515
+ description: "Frontalis (lateral)",
516
+ bilateral: true,
517
+ arkitMapping: ["browOuterUpLeft", "browOuterUpRight"]
518
+ },
519
+ {
520
+ id: 4,
521
+ name: "Brow Lowerer",
522
+ region: "brow",
523
+ description: "Corrugator supercilii + Depressor supercilii",
524
+ bilateral: true,
525
+ arkitMapping: ["browDownLeft", "browDownRight"]
526
+ },
527
+ // Upper Face — Eyes
528
+ {
529
+ id: 5,
530
+ name: "Upper Lid Raise",
531
+ region: "eye",
532
+ description: "Levator palpebrae superioris",
533
+ bilateral: true,
534
+ arkitMapping: ["eyeWideLeft", "eyeWideRight"]
535
+ },
536
+ {
537
+ id: 6,
538
+ name: "Cheek Raise",
539
+ region: "eye",
540
+ description: "Orbicularis oculi (orbital)",
541
+ bilateral: true,
542
+ arkitMapping: ["cheekSquintLeft", "cheekSquintRight"]
543
+ },
544
+ {
545
+ id: 7,
546
+ name: "Lid Tightener",
547
+ region: "eye",
548
+ description: "Orbicularis oculi (palpebral)",
549
+ bilateral: true,
550
+ arkitMapping: ["eyeSquintLeft", "eyeSquintRight"]
551
+ },
552
+ {
553
+ id: 43,
554
+ name: "Eyes Closed",
555
+ region: "eye",
556
+ description: "Relaxation of Levator palpebrae superioris",
557
+ bilateral: true,
558
+ arkitMapping: ["eyeBlinkLeft", "eyeBlinkRight"]
559
+ },
560
+ {
561
+ id: 45,
562
+ name: "Blink",
563
+ region: "eye",
564
+ description: "Rapid Orbicularis oculi contraction",
565
+ bilateral: true,
566
+ arkitMapping: ["eyeBlinkLeft", "eyeBlinkRight"]
567
+ },
568
+ {
569
+ id: 46,
570
+ name: "Wink",
571
+ region: "eye",
572
+ description: "Unilateral Orbicularis oculi",
573
+ bilateral: false,
574
+ arkitMapping: ["eyeBlinkLeft"]
575
+ },
576
+ // Nose
577
+ {
578
+ id: 9,
579
+ name: "Nose Wrinkler",
580
+ region: "nose",
581
+ description: "Levator labii superioris alaeque nasi",
582
+ bilateral: true,
583
+ arkitMapping: ["noseSneerLeft", "noseSneerRight"]
584
+ },
585
+ {
586
+ id: 10,
587
+ name: "Upper Lip Raiser",
588
+ region: "nose",
589
+ description: "Levator labii superioris",
590
+ bilateral: true
591
+ },
592
+ {
593
+ id: 11,
594
+ name: "Nasolabial Deepener",
595
+ region: "nose",
596
+ description: "Zygomaticus minor",
597
+ bilateral: true
598
+ },
599
+ // Mouth — Lip Position
600
+ {
601
+ id: 12,
602
+ name: "Lip Corner Puller",
603
+ region: "mouth",
604
+ description: "Zygomaticus major",
605
+ bilateral: true,
606
+ arkitMapping: ["mouthSmileLeft", "mouthSmileRight"]
607
+ },
608
+ {
609
+ id: 13,
610
+ name: "Sharp Lip Puller",
611
+ region: "mouth",
612
+ description: "Levator anguli oris (caninus)",
613
+ bilateral: true
614
+ },
615
+ {
616
+ id: 14,
617
+ name: "Dimpler",
618
+ region: "mouth",
619
+ description: "Buccinator",
620
+ bilateral: true,
621
+ arkitMapping: ["mouthDimpleLeft", "mouthDimpleRight"]
622
+ },
623
+ {
624
+ id: 15,
625
+ name: "Lip Corner Depressor",
626
+ region: "mouth",
627
+ description: "Depressor anguli oris (triangularis)",
628
+ bilateral: true,
629
+ arkitMapping: ["mouthFrownLeft", "mouthFrownRight"]
630
+ },
631
+ {
632
+ id: 16,
633
+ name: "Lower Lip Depressor",
634
+ region: "mouth",
635
+ description: "Depressor labii inferioris",
636
+ bilateral: true,
637
+ arkitMapping: ["mouthLowerDownLeft", "mouthLowerDownRight"]
638
+ },
639
+ { id: 17, name: "Chin Raiser", region: "mouth", description: "Mentalis", bilateral: false },
640
+ {
641
+ id: 18,
642
+ name: "Lip Pucker",
643
+ region: "mouth",
644
+ description: "Incisivii labii + Orbicularis oris",
645
+ bilateral: false,
646
+ arkitMapping: ["mouthPucker"]
647
+ },
648
+ {
649
+ id: 20,
650
+ name: "Lip Stretcher",
651
+ region: "mouth",
652
+ description: "Risorius + Platysma",
653
+ bilateral: true,
654
+ arkitMapping: ["mouthStretchLeft", "mouthStretchRight"]
655
+ },
656
+ {
657
+ id: 22,
658
+ name: "Lip Funneler",
659
+ region: "mouth",
660
+ description: "Orbicularis oris",
661
+ bilateral: false,
662
+ arkitMapping: ["mouthFunnel"]
663
+ },
664
+ {
665
+ id: 23,
666
+ name: "Lip Tightener",
667
+ region: "mouth",
668
+ description: "Orbicularis oris",
669
+ bilateral: false,
670
+ arkitMapping: ["mouthPressLeft", "mouthPressRight"]
671
+ },
672
+ {
673
+ id: 24,
674
+ name: "Lip Pressor",
675
+ region: "mouth",
676
+ description: "Orbicularis oris",
677
+ bilateral: false
678
+ },
679
+ {
680
+ id: 25,
681
+ name: "Lips Part",
682
+ region: "mouth",
683
+ description: "Depressor labii + Mentalis",
684
+ bilateral: false
685
+ },
686
+ {
687
+ id: 26,
688
+ name: "Jaw Drop",
689
+ region: "jaw",
690
+ description: "Masseter + internal pterygoid relaxation",
691
+ bilateral: false,
692
+ arkitMapping: ["jawOpen"]
693
+ },
694
+ {
695
+ id: 27,
696
+ name: "Mouth Stretch",
697
+ region: "jaw",
698
+ description: "Pterygoids + Digastric",
699
+ bilateral: false
700
+ },
701
+ {
702
+ id: 28,
703
+ name: "Lip Suck",
704
+ region: "mouth",
705
+ description: "Mentalis",
706
+ bilateral: false,
707
+ arkitMapping: ["mouthRollLower", "mouthRollUpper"]
708
+ },
709
+ // Tongue & Cheeks
710
+ {
711
+ id: 19,
712
+ name: "Tongue Show",
713
+ region: "tongue",
714
+ description: "Tongue protrusion",
715
+ bilateral: false,
716
+ arkitMapping: ["tongueOut"]
717
+ },
718
+ { id: 21, name: "Neck Tightener", region: "jaw", description: "Platysma", bilateral: false },
719
+ {
720
+ id: 29,
721
+ name: "Jaw Thrust",
722
+ region: "jaw",
723
+ description: "External pterygoid",
724
+ bilateral: false,
725
+ arkitMapping: ["jawForward"]
726
+ },
727
+ {
728
+ id: 30,
729
+ name: "Jaw Sideways",
730
+ region: "jaw",
731
+ description: "Lateral pterygoid",
732
+ bilateral: false,
733
+ arkitMapping: ["jawLeft", "jawRight"]
734
+ },
735
+ {
736
+ id: 31,
737
+ name: "Jaw Clench",
738
+ region: "jaw",
739
+ description: "Masseter + Temporalis",
740
+ bilateral: false
741
+ },
742
+ {
743
+ id: 32,
744
+ name: "Lip Bite",
745
+ region: "mouth",
746
+ description: "Lower lip drawn under upper teeth",
747
+ bilateral: false
748
+ },
749
+ {
750
+ id: 33,
751
+ name: "Cheek Blow",
752
+ region: "cheek",
753
+ description: "Buccinator expansion",
754
+ bilateral: true,
755
+ arkitMapping: ["cheekPuff"]
756
+ },
757
+ {
758
+ id: 34,
759
+ name: "Cheek Puff",
760
+ region: "cheek",
761
+ description: "Unilateral cheek inflation",
762
+ bilateral: false
763
+ },
764
+ {
765
+ id: 35,
766
+ name: "Cheek Suck",
767
+ region: "cheek",
768
+ description: "Buccinator contraction",
769
+ bilateral: true
770
+ },
771
+ {
772
+ id: 36,
773
+ name: "Tongue Bulge",
774
+ region: "tongue",
775
+ description: "Tongue pressed into cheek",
776
+ bilateral: false
777
+ },
778
+ { id: 37, name: "Lip Wipe", region: "mouth", description: "Tongue wipes lips", bilateral: false },
779
+ {
780
+ id: 38,
781
+ name: "Nostril Dilator",
782
+ region: "nose",
783
+ description: "Nasalis (alar)",
784
+ bilateral: true
785
+ },
786
+ {
787
+ id: 39,
788
+ name: "Nostril Compressor",
789
+ region: "nose",
790
+ description: "Nasalis (transverse)",
791
+ bilateral: true
792
+ },
793
+ // Head Position
794
+ {
795
+ id: 51,
796
+ name: "Head Turn Left",
797
+ region: "head",
798
+ description: "Neck rotation left",
799
+ bilateral: false
800
+ },
801
+ {
802
+ id: 52,
803
+ name: "Head Turn Right",
804
+ region: "head",
805
+ description: "Neck rotation right",
806
+ bilateral: false
807
+ },
808
+ { id: 53, name: "Head Up", region: "head", description: "Neck extension", bilateral: false },
809
+ { id: 54, name: "Head Down", region: "head", description: "Neck flexion", bilateral: false },
810
+ {
811
+ id: 55,
812
+ name: "Head Tilt Left",
813
+ region: "head",
814
+ description: "Lateral neck flexion left",
815
+ bilateral: false
816
+ },
817
+ {
818
+ id: 56,
819
+ name: "Head Tilt Right",
820
+ region: "head",
821
+ description: "Lateral neck flexion right",
822
+ bilateral: false
823
+ },
824
+ {
825
+ id: 57,
826
+ name: "Head Forward",
827
+ region: "head",
828
+ description: "Cervical protraction",
829
+ bilateral: false
830
+ },
831
+ {
832
+ id: 58,
833
+ name: "Head Back",
834
+ region: "head",
835
+ description: "Cervical retraction",
836
+ bilateral: false
837
+ },
838
+ // Eye Gaze
839
+ {
840
+ id: 61,
841
+ name: "Eyes Turn Left",
842
+ region: "gaze",
843
+ description: "Lateral rectus (left), Medial rectus (right)",
844
+ bilateral: false,
845
+ arkitMapping: ["eyeLookOutLeft", "eyeLookInRight"]
846
+ },
847
+ {
848
+ id: 62,
849
+ name: "Eyes Turn Right",
850
+ region: "gaze",
851
+ description: "Medial rectus (left), Lateral rectus (right)",
852
+ bilateral: false,
853
+ arkitMapping: ["eyeLookInLeft", "eyeLookOutRight"]
854
+ },
855
+ {
856
+ id: 63,
857
+ name: "Eyes Up",
858
+ region: "gaze",
859
+ description: "Superior rectus",
860
+ bilateral: false,
861
+ arkitMapping: ["eyeLookUpLeft", "eyeLookUpRight"]
862
+ },
863
+ {
864
+ id: 64,
865
+ name: "Eyes Down",
866
+ region: "gaze",
867
+ description: "Inferior rectus",
868
+ bilateral: false,
869
+ arkitMapping: ["eyeLookDownLeft", "eyeLookDownRight"]
870
+ }
871
+ ];
872
+ var EXPRESSION_PRESETS = [
873
+ { name: "happy", weights: { 6: 0.8, 12: 1 } },
874
+ { name: "sad", weights: { 1: 0.6, 4: 0.3, 15: 0.8 } },
875
+ { name: "angry", weights: { 4: 1, 5: 0.5, 7: 0.6, 23: 0.8 } },
876
+ { name: "surprised", weights: { 1: 1, 2: 1, 5: 0.8, 26: 0.7 } },
877
+ { name: "disgusted", weights: { 9: 0.9, 10: 0.7, 17: 0.4 } },
878
+ { name: "fearful", weights: { 1: 1, 2: 0.8, 4: 0.5, 5: 0.8, 20: 0.9 } },
879
+ { name: "contempt", weights: { 12: 0.5, 14: 0.7 } },
880
+ { name: "thinking", weights: { 4: 0.4, 7: 0.3, 28: 0.5 } },
881
+ { name: "confused", weights: { 1: 0.5, 4: 0.6, 7: 0.3, 15: 0.3 } },
882
+ { name: "smirk", weights: { 12: 0.7, 14: 0.4 } }
883
+ ];
884
+ var VISEME_15 = [
885
+ { name: "sil", phonemes: ["(silence)"], weights: {} },
886
+ { name: "aa", phonemes: ["ah", "father"], weights: { 25: 0.8, 26: 0.5 } },
887
+ { name: "ee", phonemes: ["ee", "see"], weights: { 25: 0.4, 12: 0.3 } },
888
+ { name: "ih", phonemes: ["ih", "bit"], weights: { 25: 0.3, 20: 0.2 } },
889
+ { name: "oh", phonemes: ["oh", "go"], weights: { 25: 0.6, 27: 0.4 } },
890
+ { name: "oo", phonemes: ["oo", "too"], weights: { 25: 0.3, 10: 0.2 } },
891
+ { name: "pp", phonemes: ["pp", "bb", "mm"], weights: { 28: 0.8 } },
892
+ { name: "ff", phonemes: ["ff", "vv"], weights: { 25: 0.1, 10: 0.4 } },
893
+ { name: "th", phonemes: ["th"], weights: { 25: 0.3, 19: 0.5 } },
894
+ { name: "dd", phonemes: ["dd", "tt", "nn"], weights: { 25: 0.2, 19: 0.3 } },
895
+ { name: "kk", phonemes: ["kk", "gg"], weights: { 25: 0.2, 26: 0.3 } },
896
+ { name: "ch", phonemes: ["ch", "jj", "sh"], weights: { 25: 0.3, 22: 0.4 } },
897
+ { name: "ss", phonemes: ["ss", "zz"], weights: { 25: 0.15, 20: 0.3 } },
898
+ { name: "nn", phonemes: ["ng"], weights: { 25: 0.1, 26: 0.15 } },
899
+ { name: "rr", phonemes: ["rr", "ll"], weights: { 25: 0.25, 22: 0.2 } }
900
+ ];
901
+ function computeSparseMorphTarget(name, neutral, deformed, epsilon = 1e-4) {
902
+ const totalVertices = neutral.length / 3;
903
+ const deltas = [];
904
+ for (let i = 0; i < totalVertices; i++) {
905
+ const i3 = i * 3;
906
+ const dx = deformed[i3] - neutral[i3];
907
+ const dy = deformed[i3 + 1] - neutral[i3 + 1];
908
+ const dz = deformed[i3 + 2] - neutral[i3 + 2];
909
+ const magnitude = Math.sqrt(dx * dx + dy * dy + dz * dz);
910
+ if (magnitude > epsilon) {
911
+ deltas.push({ vertexIndex: i, delta: [dx, dy, dz] });
912
+ }
913
+ }
914
+ return { name, deltas, totalVertices };
915
+ }
916
+ function applyMorphTargets(basePositions, targets) {
917
+ for (const { target, weight } of targets) {
918
+ if (weight === 0) continue;
919
+ for (const delta of target.deltas) {
920
+ const i3 = delta.vertexIndex * 3;
921
+ basePositions[i3] += delta.delta[0] * weight;
922
+ basePositions[i3 + 1] += delta.delta[1] * weight;
923
+ basePositions[i3 + 2] += delta.delta[2] * weight;
924
+ }
925
+ }
926
+ }
927
+ function evaluateExpression(expressionName) {
928
+ const preset = EXPRESSION_PRESETS.find((e) => e.name === expressionName);
929
+ return preset ? { ...preset.weights } : {};
930
+ }
931
+ function getActionUnit(id) {
932
+ return FACS_ACTION_UNITS.find((au) => au.id === id);
933
+ }
934
+ function getViseme(name) {
935
+ return VISEME_15.find((v) => v.name === name);
936
+ }
937
+
938
+ // src/character/LipSyncEngine.ts
939
+ var DEFAULT_LIP_SYNC_CONFIG = {
940
+ method: "rhubarb",
941
+ blendSpeed: 0.08,
942
+ emotionOverlay: true,
943
+ emotionBlend: 0.3,
944
+ smoothing: 0.4
945
+ };
946
+ var LipSyncEngine = class {
947
+ config;
948
+ currentWeights = /* @__PURE__ */ new Map();
949
+ targetWeights = /* @__PURE__ */ new Map();
950
+ visemeMap = /* @__PURE__ */ new Map();
951
+ constructor(config) {
952
+ this.config = { ...DEFAULT_LIP_SYNC_CONFIG, ...config };
953
+ for (const v of VISEME_15) {
954
+ this.visemeMap.set(v.name, v);
955
+ }
956
+ }
957
+ /**
958
+ * Get the interpolated AU weights for a given time position in a lip sync track.
959
+ *
960
+ * @param track - The lip sync track with viseme keyframes
961
+ * @param time - Current time position in seconds
962
+ * @param emotion - Optional emotion name for overlay (e.g., 'happy', 'sad')
963
+ * @param emotionIntensity - Emotion intensity 0-1
964
+ * @returns Map of FACS AU id → weight
965
+ */
966
+ evaluate(track, time, emotion, emotionIntensity = 1) {
967
+ const { prev, next, t } = this.findBracketingKeyframes(track, time);
968
+ this.targetWeights.clear();
969
+ if (prev && next && t > 0) {
970
+ const prevDef = this.visemeMap.get(prev.viseme);
971
+ const nextDef = this.visemeMap.get(next.viseme);
972
+ const prevWeight = prev.weight ?? 1;
973
+ const nextWeight = next.weight ?? 1;
974
+ if (prevDef) {
975
+ for (const [auStr, w] of Object.entries(prevDef.weights)) {
976
+ const au = Number(auStr);
977
+ const current = this.targetWeights.get(au) ?? 0;
978
+ this.targetWeights.set(au, current + w * prevWeight * (1 - t));
979
+ }
980
+ }
981
+ if (nextDef) {
982
+ for (const [auStr, w] of Object.entries(nextDef.weights)) {
983
+ const au = Number(auStr);
984
+ const current = this.targetWeights.get(au) ?? 0;
985
+ this.targetWeights.set(au, current + w * nextWeight * t);
986
+ }
987
+ }
988
+ } else if (prev) {
989
+ const prevDef = this.visemeMap.get(prev.viseme);
990
+ const prevWeight = prev.weight ?? 1;
991
+ if (prevDef) {
992
+ for (const [auStr, w] of Object.entries(prevDef.weights)) {
993
+ this.targetWeights.set(Number(auStr), w * prevWeight);
994
+ }
995
+ }
996
+ }
997
+ if (this.config.emotionOverlay && emotion) {
998
+ const emotionPreset = EXPRESSION_PRESETS.find((e) => e.name === emotion);
999
+ if (emotionPreset) {
1000
+ const emoBlend = this.config.emotionBlend * emotionIntensity;
1001
+ const visBlend = 1 - emoBlend;
1002
+ for (const [au, w] of this.targetWeights.entries()) {
1003
+ this.targetWeights.set(au, w * visBlend);
1004
+ }
1005
+ for (const [auStr, w] of Object.entries(emotionPreset.weights)) {
1006
+ const au = Number(auStr);
1007
+ const current = this.targetWeights.get(au) ?? 0;
1008
+ this.targetWeights.set(au, current + w * emoBlend);
1009
+ }
1010
+ }
1011
+ }
1012
+ const alpha = this.config.smoothing;
1013
+ for (const [au, target] of this.targetWeights.entries()) {
1014
+ const current = this.currentWeights.get(au) ?? 0;
1015
+ this.currentWeights.set(au, current + (target - current) * alpha);
1016
+ }
1017
+ for (const [au, current] of this.currentWeights.entries()) {
1018
+ if (!this.targetWeights.has(au)) {
1019
+ const decayed = current * (1 - alpha);
1020
+ if (decayed < 1e-3) {
1021
+ this.currentWeights.delete(au);
1022
+ } else {
1023
+ this.currentWeights.set(au, decayed);
1024
+ }
1025
+ }
1026
+ }
1027
+ return new Map(this.currentWeights);
1028
+ }
1029
+ /**
1030
+ * Reset the engine state. Call when switching audio tracks.
1031
+ */
1032
+ reset() {
1033
+ this.currentWeights.clear();
1034
+ this.targetWeights.clear();
1035
+ }
1036
+ /**
1037
+ * Get the current configuration.
1038
+ */
1039
+ getConfig() {
1040
+ return this.config;
1041
+ }
1042
+ // ---------------------------------------------------------------------------
1043
+ // Private
1044
+ // ---------------------------------------------------------------------------
1045
+ findBracketingKeyframes(track, time) {
1046
+ if (track.keyframes.length === 0) return { t: 0 };
1047
+ if (time <= track.keyframes[0].time) {
1048
+ return { prev: track.keyframes[0], t: 0 };
1049
+ }
1050
+ if (time >= track.keyframes[track.keyframes.length - 1].time) {
1051
+ return { prev: track.keyframes[track.keyframes.length - 1], t: 0 };
1052
+ }
1053
+ for (let i = 0; i < track.keyframes.length - 1; i++) {
1054
+ const a = track.keyframes[i];
1055
+ const b = track.keyframes[i + 1];
1056
+ if (time >= a.time && time <= b.time) {
1057
+ const duration = b.time - a.time;
1058
+ const t = duration > 0 ? (time - a.time) / duration : 0;
1059
+ return { prev: a, next: b, t };
1060
+ }
1061
+ }
1062
+ return { prev: track.keyframes[track.keyframes.length - 1], t: 0 };
1063
+ }
1064
+ };
1065
+
1066
+ // src/character/IdleBehaviorSystem.ts
1067
+ var DEFAULT_CONFIG = {
1068
+ breathsPerMinute: 12,
1069
+ chestAmplitude: 0.035,
1070
+ nostrilAmplitude: 0.22,
1071
+ blinkIntervalRangeSec: [2.4, 5.2],
1072
+ blinkDurationSec: 0.12,
1073
+ microSaccadeIntervalRangeSec: [0.7, 1.6],
1074
+ microSaccadeAmplitude: 0.03
1075
+ };
1076
+ function clamp01(v) {
1077
+ return Math.max(0, Math.min(1, v));
1078
+ }
1079
+ function lerp(a, b, t) {
1080
+ return a + (b - a) * t;
1081
+ }
1082
+ var IdleBehaviorSystem = class {
1083
+ bindings;
1084
+ config;
1085
+ rnd;
1086
+ elapsedSec = 0;
1087
+ nextBlinkSec = 0;
1088
+ blinkT = 0;
1089
+ nextSaccadeSec = 0;
1090
+ saccadeTarget = { x: 0, y: 0 };
1091
+ gaze = { x: 0, y: 0 };
1092
+ constructor(bindings, config = {}) {
1093
+ this.bindings = bindings;
1094
+ this.config = {
1095
+ breathsPerMinute: config.breathsPerMinute ?? DEFAULT_CONFIG.breathsPerMinute,
1096
+ chestAmplitude: config.chestAmplitude ?? DEFAULT_CONFIG.chestAmplitude,
1097
+ nostrilAmplitude: config.nostrilAmplitude ?? DEFAULT_CONFIG.nostrilAmplitude,
1098
+ blinkIntervalRangeSec: config.blinkIntervalRangeSec ?? DEFAULT_CONFIG.blinkIntervalRangeSec,
1099
+ blinkDurationSec: config.blinkDurationSec ?? DEFAULT_CONFIG.blinkDurationSec,
1100
+ microSaccadeIntervalRangeSec: config.microSaccadeIntervalRangeSec ?? DEFAULT_CONFIG.microSaccadeIntervalRangeSec,
1101
+ microSaccadeAmplitude: config.microSaccadeAmplitude ?? DEFAULT_CONFIG.microSaccadeAmplitude
1102
+ };
1103
+ this.rnd = config.random ?? Math.random;
1104
+ this.scheduleNextBlink();
1105
+ this.scheduleNextSaccade();
1106
+ }
1107
+ /** Force an immediate blink cycle. Useful for deterministic tests and scripted beats. */
1108
+ triggerBlink() {
1109
+ this.blinkT = this.config.blinkDurationSec;
1110
+ }
1111
+ update(deltaSec) {
1112
+ if (deltaSec <= 0) {
1113
+ return this.computeFrame();
1114
+ }
1115
+ const prevElapsedSec = this.elapsedSec;
1116
+ this.elapsedSec += deltaSec;
1117
+ if (this.blinkT > 0) {
1118
+ this.blinkT = Math.max(0, this.blinkT - deltaSec);
1119
+ }
1120
+ if (prevElapsedSec < this.nextBlinkSec && this.elapsedSec >= this.nextBlinkSec) {
1121
+ const overshoot = this.elapsedSec - this.nextBlinkSec;
1122
+ this.blinkT = Math.max(0, this.config.blinkDurationSec - overshoot);
1123
+ this.scheduleNextBlink();
1124
+ }
1125
+ if (this.elapsedSec >= this.nextSaccadeSec) {
1126
+ const a = this.config.microSaccadeAmplitude;
1127
+ this.saccadeTarget = {
1128
+ x: lerp(-a, a, this.rnd()),
1129
+ y: lerp(-a, a, this.rnd())
1130
+ };
1131
+ this.scheduleNextSaccade();
1132
+ }
1133
+ const settle = clamp01(deltaSec * 18);
1134
+ this.gaze.x = lerp(this.gaze.x, this.saccadeTarget.x, settle);
1135
+ this.gaze.y = lerp(this.gaze.y, this.saccadeTarget.y, settle);
1136
+ return this.computeFrame();
1137
+ }
1138
+ computeFrame() {
1139
+ const breathHz = this.config.breathsPerMinute / 60;
1140
+ const breath = Math.sin(this.elapsedSec * breathHz * Math.PI * 2);
1141
+ const inhale = Math.max(0, breath);
1142
+ const nostril = Math.pow(inhale, 1.65) * this.config.nostrilAmplitude;
1143
+ const blink = this.computeBlinkWeight();
1144
+ const boneScale = {};
1145
+ if (this.bindings.chestBone) {
1146
+ boneScale[this.bindings.chestBone] = 1 + breath * this.config.chestAmplitude;
1147
+ }
1148
+ const morphWeights = {};
1149
+ if (this.bindings.eyelidLeft) morphWeights[this.bindings.eyelidLeft] = blink;
1150
+ if (this.bindings.eyelidRight) morphWeights[this.bindings.eyelidRight] = blink;
1151
+ if (this.bindings.nostrilFlare) morphWeights[this.bindings.nostrilFlare] = nostril;
1152
+ return {
1153
+ boneScale,
1154
+ morphWeights,
1155
+ gazeOffset: { ...this.gaze },
1156
+ blink,
1157
+ breath
1158
+ };
1159
+ }
1160
+ computeBlinkWeight() {
1161
+ if (this.blinkT <= 0) return 0;
1162
+ const total = this.config.blinkDurationSec;
1163
+ const progress = 1 - this.blinkT / total;
1164
+ if (progress <= 0.5) {
1165
+ return clamp01(progress / 0.5);
1166
+ }
1167
+ return clamp01((1 - progress) / 0.5);
1168
+ }
1169
+ scheduleNextBlink() {
1170
+ const [minS, maxS] = this.config.blinkIntervalRangeSec;
1171
+ this.nextBlinkSec = this.elapsedSec + lerp(minS, maxS, this.rnd());
1172
+ }
1173
+ scheduleNextSaccade() {
1174
+ const [minS, maxS] = this.config.microSaccadeIntervalRangeSec;
1175
+ this.nextSaccadeSec = this.elapsedSec + lerp(minS, maxS, this.rnd());
1176
+ }
1177
+ };
1178
+ function createIdleBehaviorSystem(bindings, config) {
1179
+ return new IdleBehaviorSystem(bindings, config);
1180
+ }
1181
+
1182
+ export {
1183
+ PIPELINE_STAGES,
1184
+ HUMANOID_BONE_NAMES,
1185
+ HUMANOID_65_SKELETON,
1186
+ MIXAMO_BONE_MAP,
1187
+ VRM_BONE_MAP,
1188
+ getBoneChildren,
1189
+ getBoneChain,
1190
+ validateSkeleton,
1191
+ FACS_ACTION_UNITS,
1192
+ EXPRESSION_PRESETS,
1193
+ VISEME_15,
1194
+ computeSparseMorphTarget,
1195
+ applyMorphTargets,
1196
+ evaluateExpression,
1197
+ getActionUnit,
1198
+ getViseme,
1199
+ DEFAULT_LIP_SYNC_CONFIG,
1200
+ LipSyncEngine,
1201
+ IdleBehaviorSystem,
1202
+ createIdleBehaviorSystem,
1203
+ character_exports
1204
+ };