distark-render 1.0.1 → 1.0.3

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 (44) hide show
  1. package/README.md +154 -73
  2. package/dist/modules/adapters/p5Renderer.d.ts +0 -0
  3. package/dist/modules/adapters/p5Renderer.d.ts.map +0 -0
  4. package/dist/modules/adapters/p5Renderer.js +0 -0
  5. package/dist/modules/adapters/p5Renderer.js.map +0 -0
  6. package/dist/modules/adapters/skiaRenderer.d.ts +0 -0
  7. package/dist/modules/adapters/skiaRenderer.d.ts.map +1 -1
  8. package/dist/modules/adapters/skiaRenderer.js +11 -0
  9. package/dist/modules/adapters/skiaRenderer.js.map +1 -1
  10. package/dist/modules/eyeSystem.d.ts +34 -1
  11. package/dist/modules/eyeSystem.d.ts.map +1 -1
  12. package/dist/modules/eyeSystem.js +46 -10
  13. package/dist/modules/eyeSystem.js.map +1 -1
  14. package/dist/modules/imageLoad.d.ts +0 -0
  15. package/dist/modules/imageLoad.d.ts.map +1 -1
  16. package/dist/modules/imageLoad.js +16 -0
  17. package/dist/modules/imageLoad.js.map +1 -1
  18. package/dist/modules/mouthSystem.d.ts +15 -15
  19. package/dist/modules/mouthSystem.d.ts.map +1 -1
  20. package/dist/modules/mouthSystem.js +91 -52
  21. package/dist/modules/mouthSystem.js.map +1 -1
  22. package/dist/modules/renderRig.d.ts +0 -0
  23. package/dist/modules/renderRig.d.ts.map +1 -1
  24. package/dist/modules/renderRig.js +92 -16
  25. package/dist/modules/renderRig.js.map +1 -1
  26. package/dist/tests/test-joint-movement.d.ts +7 -0
  27. package/dist/tests/test-joint-movement.d.ts.map +1 -0
  28. package/dist/tests/test-joint-movement.js +323 -0
  29. package/dist/tests/test-joint-movement.js.map +1 -0
  30. package/dist/{test-skia.d.ts → tests/test-skia.d.ts} +0 -0
  31. package/dist/tests/test-skia.d.ts.map +1 -0
  32. package/dist/{test-skia.js → tests/test-skia.js} +1 -1
  33. package/dist/tests/test-skia.js.map +1 -0
  34. package/dist/tests/test-visual-verification.d.ts +7 -0
  35. package/dist/tests/test-visual-verification.d.ts.map +1 -0
  36. package/dist/tests/test-visual-verification.js +180 -0
  37. package/dist/tests/test-visual-verification.js.map +1 -0
  38. package/dist/types.d.ts +18 -0
  39. package/dist/types.d.ts.map +1 -1
  40. package/dist/types.js +0 -0
  41. package/dist/types.js.map +0 -0
  42. package/package.json +5 -2
  43. package/dist/test-skia.d.ts.map +0 -1
  44. package/dist/test-skia.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"mouthSystem.d.ts","sourceRoot":"","sources":["../../modules/mouthSystem.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mouthSystem.d.ts","sourceRoot":"","sources":["../../modules/mouthSystem.ts"],"names":[],"mappings":"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"}
@@ -15,7 +15,7 @@ export class MouthSystem {
15
15
  * @param availableMouths - Set of available mouth shapes for this character
16
16
  * @param config - Optional mouth configuration
17
17
  */
18
- constructor(characterId, availableMouths = new Set(['closed', 'neutral']), config = {}) {
18
+ constructor(characterId, availableMouths = new Set(['closed']), config = {}) {
19
19
  this.characterId = characterId;
20
20
  this.availableMouths = availableMouths;
21
21
  this.config = {
@@ -25,7 +25,7 @@ export class MouthSystem {
25
25
  visemeMapping: config.visemeMapping ?? MouthSystem.DEFAULT_VISEME_MAPPING
26
26
  };
27
27
  this.state = {
28
- currentMouthKey: 'neutral',
28
+ currentMouthKey: 'closed',
29
29
  lastMouthChangeTime: 0,
30
30
  currentVolume: 0,
31
31
  mode: 'manual'
@@ -51,9 +51,6 @@ export class MouthSystem {
51
51
  this.state.currentMouthKey = shape;
52
52
  this.state.mode = 'manual';
53
53
  }
54
- else {
55
- console.warn(`Mouth shape "${shape}" not available for character ${this.characterId}`);
56
- }
57
54
  }
58
55
  /**
59
56
  * Set available mouth shapes
@@ -81,7 +78,7 @@ export class MouthSystem {
81
78
  // Update mouth based on volume
82
79
  if (avgVolume < (this.config.volumeThreshold ?? 10)) {
83
80
  // Low volume: close mouth
84
- this.state.currentMouthKey = this.availableMouths.has('neutral') ? 'neutral' : 'closed';
81
+ this.state.currentMouthKey = 'closed';
85
82
  }
86
83
  else {
87
84
  // Speaking: change mouth shape periodically
@@ -94,8 +91,8 @@ export class MouthSystem {
94
91
  this.state.currentMouthKey = availableTalkingMouths[randomIndex];
95
92
  }
96
93
  else {
97
- // Fallback: use any available mouth except neutral/closed
98
- const fallbackMouths = Array.from(this.availableMouths).filter(m => m !== 'neutral' && m !== 'closed');
94
+ // Fallback: use any available mouth except closed
95
+ const fallbackMouths = Array.from(this.availableMouths).filter(m => m !== 'closed');
99
96
  if (fallbackMouths.length > 0) {
100
97
  const randomIndex = Math.floor(Math.random() * fallbackMouths.length);
101
98
  this.state.currentMouthKey = fallbackMouths[randomIndex];
@@ -106,9 +103,9 @@ export class MouthSystem {
106
103
  }
107
104
  }
108
105
  else {
109
- // No audio or paused: reset to neutral
106
+ // No audio or paused: reset to closed
110
107
  this.state.currentVolume = 0;
111
- this.state.currentMouthKey = this.availableMouths.has('neutral') ? 'neutral' : 'closed';
108
+ this.state.currentMouthKey = 'closed';
112
109
  }
113
110
  }
114
111
  /**
@@ -124,14 +121,14 @@ export class MouthSystem {
124
121
  }
125
122
  else {
126
123
  // Fallback to closed if viseme not found
127
- this.state.currentMouthKey = this.availableMouths.has('closed') ? 'closed' : 'neutral';
124
+ this.state.currentMouthKey = 'closed';
128
125
  }
129
126
  }
130
127
  /**
131
- * Reset mouth to neutral/closed state
128
+ * Reset mouth to closed state
132
129
  */
133
130
  reset() {
134
- this.state.currentMouthKey = this.availableMouths.has('neutral') ? 'neutral' : 'closed';
131
+ this.state.currentMouthKey = 'closed';
135
132
  this.state.currentVolume = 0;
136
133
  this.state.lastMouthChangeTime = 0;
137
134
  this.state.mode = 'manual';
@@ -143,19 +140,19 @@ export class MouthSystem {
143
140
  * @returns The image key for the current mouth (e.g., 'imagePaths.mouth_open')
144
141
  */
145
142
  getCurrentMouthImageKey() {
146
- const currentMouth = this.state.currentMouthKey === 'neutral' ? 'closed' : this.state.currentMouthKey;
143
+ const currentMouth = this.state.currentMouthKey;
147
144
  // Map mouth shape to possible image key variations
148
145
  const keyMappings = {
149
- 'closed': ['mouth_closed', 'closed', 'neutral'],
150
- 'slightly-open': ['mouth_slightly_open', 'slightly-open', 'half-open'],
151
- 'half-open': ['mouth_half_open', 'half-open', 'slightly-open'],
152
- 'open': ['mouth_open', 'open'],
153
- 'wide-open': ['mouth_wide_open', 'wide-open'],
154
- 'ah': ['mouth_ah', 'ah'],
155
- 'ee': ['mouth_ee', 'ee'],
156
- 'woo': ['mouth_woo', 'woo'],
157
- 'ds': ['mouth_ds', 'ds'],
158
- 'neutral': ['mouth_closed', 'closed', 'neutral']
146
+ 'f': ['f', 'mouth_f'],
147
+ 'l': ['l', 'mouth_l'],
148
+ 'ds': ['ds', 'mouth_ds'],
149
+ 'ee': ['ee', 'mouth_ee'],
150
+ 'eh': ['eh', 'mouth_eh'],
151
+ 'open': ['open', 'mouth_open'],
152
+ 'closed': ['closed', 'mouth_closed'],
153
+ 'half-open': ['half-open', 'half_open', 'mouth_half_open'],
154
+ 'wide-open': ['wide-open', 'wide_open', 'mouth_wide_open'],
155
+ 'slightly-open': ['slightly-open', 'slightly_open', 'mouth_slightly_open']
159
156
  };
160
157
  const candidates = keyMappings[currentMouth] || [currentMouth];
161
158
  // Return the first candidate (renderRig will try all variants)
@@ -166,18 +163,18 @@ export class MouthSystem {
166
163
  * Used by renderRig to try multiple image name variations
167
164
  */
168
165
  getMouthImageKeyCandidates() {
169
- const currentMouth = this.state.currentMouthKey === 'neutral' ? 'closed' : this.state.currentMouthKey;
166
+ const currentMouth = this.state.currentMouthKey;
170
167
  const keyMappings = {
171
- 'closed': ['mouth_closed', 'closed', 'neutral'],
172
- 'slightly-open': ['mouth_slightly_open', 'slightly-open', 'half-open'],
173
- 'half-open': ['mouth_half_open', 'half-open', 'slightly-open'],
174
- 'open': ['mouth_open', 'open'],
175
- 'wide-open': ['mouth_wide_open', 'wide-open'],
176
- 'ah': ['mouth_ah', 'ah'],
177
- 'ee': ['mouth_ee', 'ee'],
178
- 'woo': ['mouth_woo', 'woo'],
179
- 'ds': ['mouth_ds', 'ds'],
180
- 'neutral': ['mouth_closed', 'closed', 'neutral']
168
+ 'f': ['f', 'mouth_f'],
169
+ 'l': ['l', 'mouth_l'],
170
+ 'ds': ['ds', 'mouth_ds'],
171
+ 'ee': ['ee', 'mouth_ee'],
172
+ 'eh': ['eh', 'mouth_eh'],
173
+ 'open': ['open', 'mouth_open'],
174
+ 'closed': ['closed', 'mouth_closed'],
175
+ 'half-open': ['half-open', 'half_open', 'mouth_half_open'],
176
+ 'wide-open': ['wide-open', 'wide_open', 'mouth_wide_open'],
177
+ 'slightly-open': ['slightly-open', 'slightly_open', 'mouth_slightly_open']
181
178
  };
182
179
  return keyMappings[currentMouth] || [currentMouth];
183
180
  }
@@ -206,6 +203,7 @@ export class MouthSystem {
206
203
  }
207
204
  /**
208
205
  * Default viseme to mouth shape mapping
206
+ * Maps phonemes to actual available mouth shapes
209
207
  */
210
208
  MouthSystem.DEFAULT_VISEME_MAPPING = {
211
209
  'X': 'closed',
@@ -214,24 +212,24 @@ MouthSystem.DEFAULT_VISEME_MAPPING = {
214
212
  'C': 'half-open',
215
213
  'D': 'ds',
216
214
  'E': 'ee',
217
- 'F': 'half-open',
215
+ 'F': 'f',
218
216
  'G': 'half-open',
219
217
  'H': 'slightly-open',
220
218
  'I': 'ee',
221
219
  'J': 'slightly-open',
222
220
  'K': 'half-open',
223
- 'L': 'slightly-open',
221
+ 'L': 'l',
224
222
  'M': 'closed',
225
223
  'N': 'slightly-open',
226
- 'O': 'woo',
224
+ 'O': 'open',
227
225
  'P': 'closed',
228
- 'Q': 'woo',
226
+ 'Q': 'open',
229
227
  'R': 'slightly-open',
230
228
  'S': 'slightly-open',
231
229
  'T': 'ds',
232
- 'U': 'woo',
230
+ 'U': 'open',
233
231
  'V': 'half-open',
234
- 'W': 'woo',
232
+ 'W': 'wide-open',
235
233
  'Y': 'ee',
236
234
  'Z': 'slightly-open'
237
235
  };
@@ -243,35 +241,76 @@ MouthSystem.DEFAULT_TALKING_MOUTHS = [
243
241
  'half-open',
244
242
  'open',
245
243
  'wide-open',
246
- 'ah',
247
244
  'ee',
248
- 'woo'
245
+ 'eh',
246
+ 'f',
247
+ 'l'
249
248
  ];
250
249
  /**
251
250
  * Factory function to create mouth system
252
251
  */
253
- export function createMouthSystem(characterId, availableMouths = ['closed', 'neutral'], config = {}) {
252
+ export function createMouthSystem(characterId, availableMouths = ['closed'], config = {}) {
254
253
  return new MouthSystem(characterId, new Set(availableMouths), config);
255
254
  }
256
255
  /**
257
256
  * Helper: Extract available mouth shapes from rig data
257
+ * Only looks for the specific mouth shapes defined in MouthShape type
258
258
  */
259
259
  export function extractMouthShapesFromRigData(rigData) {
260
260
  const mouths = [];
261
+ // THE SINGLE SOURCE OF TRUTH for all mouth types
261
262
  const mouthTypes = [
262
- 'closed', 'slightly-open', 'half-open', 'ds', 'open', 'ee', 'wide-open', 'ah', 'woo', 'neutral'
263
+ 'f', 'l', 'ds', 'ee', 'eh', 'open', 'closed', 'half-open', 'wide-open', 'slightly-open'
263
264
  ];
264
- if (rigData.imagePaths) {
265
- for (const mouthType of mouthTypes) {
266
- if (rigData.imagePaths[mouthType] || rigData.imagePaths[`mouth_${mouthType}`]) {
267
- mouths.push(mouthType);
268
- }
265
+ // Check if mouth data exists
266
+ if (!rigData.mouth) {
267
+ return ['closed'];
268
+ }
269
+ const mouthData = rigData.mouth;
270
+ // Check each mouth type from our absolute list
271
+ for (const mouthType of mouthTypes) {
272
+ // Check if this exact mouth shape exists in the data
273
+ const value = mouthData[mouthType];
274
+ // Check if value exists and is valid (not undefined, not null, not [MEDIA_REMOVED])
275
+ if (value &&
276
+ typeof value === 'string' &&
277
+ value !== '' &&
278
+ !value.includes('[MEDIA_REMOVED]')) {
279
+ mouths.push(mouthType);
269
280
  }
270
281
  }
271
- // Always include at least closed/neutral as fallback
282
+ // Always include at least closed as fallback
272
283
  if (mouths.length === 0) {
273
- mouths.push('closed', 'neutral');
284
+ mouths.push('closed');
274
285
  }
275
286
  return mouths;
276
287
  }
288
+ /**
289
+ * Helper: Extract mouth image hashes from rig data
290
+ * Returns only the valid mouth shape MD5 hashes, excluding positioning data
291
+ * @param rigData - Character rig data
292
+ * @returns Object with mouth shape names as keys and MD5 hashes as values
293
+ */
294
+ export function extractMouthImagesFromRigData(rigData) {
295
+ const mouthImages = {};
296
+ // THE SINGLE SOURCE OF TRUTH for all mouth types
297
+ const mouthTypes = [
298
+ 'f', 'l', 'ds', 'ee', 'eh', 'open', 'closed', 'half-open', 'wide-open', 'slightly-open'
299
+ ];
300
+ if (!rigData.mouth) {
301
+ return mouthImages;
302
+ }
303
+ const mouthData = rigData.mouth;
304
+ // Extract only the mouth shape image hashes
305
+ for (const mouthType of mouthTypes) {
306
+ const value = mouthData[mouthType];
307
+ if (value &&
308
+ typeof value === 'string' &&
309
+ value !== '' &&
310
+ !value.includes('[MEDIA_REMOVED]')) {
311
+ mouthImages[mouthType] = value;
312
+ }
313
+ }
314
+ return mouthImages;
315
+ }
277
316
  //# sourceMappingURL=mouthSystem.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"mouthSystem.js","sourceRoot":"","sources":["../../modules/mouthSystem.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mouthSystem.js","sourceRoot":"","sources":["../../modules/mouthSystem.ts"],"names":[],"mappings":"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"}
File without changes
@@ -1 +1 @@
1
- {"version":3,"file":"renderRig.d.ts","sourceRoot":"","sources":["../../modules/renderRig.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,OAAO,KAAK,EACR,OAAO,EACP,aAAa,EACb,aAAa,EAGb,QAAQ,EACX,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,qBAAa,oBAAoB;IAC7B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;IAEnC;;;OAGG;gBACS,WAAW,CAAC,EAAE,WAAW;IAIrC;;;OAGG;IACH,cAAc,IAAI,WAAW;IAI7B;;OAEG;IACH,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACH,uBAAuB,CACnB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,aAAkB,GAC5B,aAAa;IAsvChB;;;;;;;;;;;;;;;;;OAiBG;IACG,MAAM,CACR,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CAAC,EACnE,YAAY,GAAE,QAAyB,EACvC,eAAe,GAAE,OAAc,GAChC,OAAO,CAAC,IAAI,CAAC;CA8EnB;AAGD,eAAO,MAAM,eAAe,sBAA6B,CAAC;AAG1D,wBAAsB,kBAAkB,CACpC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CAAC,EACnE,YAAY,GAAE,QAAyB,EACvC,eAAe,GAAE,OAAc,GAChC,OAAO,CAAC,IAAI,CAAC,CAEf;AAGD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,aAAkB,GAAG,aAAa,CAEpG"}
1
+ {"version":3,"file":"renderRig.d.ts","sourceRoot":"","sources":["../../modules/renderRig.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAG7C,OAAO,KAAK,EACR,OAAO,EACP,aAAa,EACb,aAAa,EAGb,QAAQ,EACX,MAAM,aAAa,CAAC;AAErB;;GAEG;AACH,qBAAa,oBAAoB;IAC7B,SAAS,CAAC,WAAW,EAAE,WAAW,CAAC;IAEnC;;;OAGG;gBACS,WAAW,CAAC,EAAE,WAAW;IAIrC;;;OAGG;IACH,cAAc,IAAI,WAAW;IAI7B;;OAEG;IACH,OAAO,CAAC,cAAc;IAYtB;;OAEG;IACH,uBAAuB,CACnB,OAAO,EAAE,OAAO,EAChB,OAAO,GAAE,aAAkB,GAC5B,aAAa;IA00ChB;;;;;;;;;;;;;;;;;OAiBG;IACG,MAAM,CACR,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CAAC,EACnE,YAAY,GAAE,QAAyB,EACvC,eAAe,GAAE,OAAc,GAChC,OAAO,CAAC,IAAI,CAAC;CA8EnB;AAGD,eAAO,MAAM,eAAe,sBAA6B,CAAC;AAG1D,wBAAsB,kBAAkB,CACpC,MAAM,EAAE,iBAAiB,EACzB,OAAO,EAAE,OAAO,EAChB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,GAAG,iBAAiB,CAAC,EACnE,YAAY,GAAE,QAAyB,EACvC,eAAe,GAAE,OAAc,GAChC,OAAO,CAAC,IAAI,CAAC,CAEf;AAGD,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,GAAE,aAAkB,GAAG,aAAa,CAEpG"}
@@ -148,11 +148,40 @@ export class CharacterRigRenderer {
148
148
  // Mouth (child of head)
149
149
  if (visibility.mouth !== false) {
150
150
  const headPivot = pivotPoints['torso_head'] || { x: 0, y: 0 };
151
- const mouthOffset = pivotPoints['head_mouth'] || { x: 0, y: 0 };
152
- const mouthWidth = dimensions.mouth?.width || 40;
153
- const mouthHeight = dimensions.mouth?.height || 30;
154
151
  const selfRot = selfRotations["mouth"] || 0;
155
152
  const headRot = rotations["head"] || 0;
153
+ // Get mouth dimensions and position from rigData.mouth
154
+ const mouthData = rigData.mouth;
155
+ let baseMouthWidth = dimensions.mouth?.width || 40;
156
+ let baseMouthHeight = dimensions.mouth?.height || 30;
157
+ let mouthSizeScale = 1;
158
+ // Determine position offset: use xCoor/yCoor from mouth data if available,
159
+ // otherwise fall back to pivot point system
160
+ const mouthPivotOffset = pivotPoints['head_mouth'] || { x: 0, y: 0 };
161
+ let mouthXOffset = mouthPivotOffset.x || 0;
162
+ let mouthYOffset = mouthPivotOffset.y || 0;
163
+ // If mouth data is available, use its width, height, size, and override position with xCoor/yCoor
164
+ if (mouthData && typeof mouthData === 'object') {
165
+ if (typeof mouthData.width === 'number' && mouthData.width > 0) {
166
+ baseMouthWidth = mouthData.width;
167
+ }
168
+ if (typeof mouthData.height === 'number' && mouthData.height > 0) {
169
+ baseMouthHeight = mouthData.height;
170
+ }
171
+ if (typeof mouthData.size === 'number' && mouthData.size > 0) {
172
+ mouthSizeScale = mouthData.size;
173
+ }
174
+ // xCoor and yCoor from mouth data take precedence over pivot points
175
+ if (typeof mouthData.xCoor === 'number') {
176
+ mouthXOffset = mouthData.xCoor;
177
+ }
178
+ if (typeof mouthData.yCoor === 'number') {
179
+ mouthYOffset = mouthData.yCoor;
180
+ }
181
+ }
182
+ // Calculate final dimensions with size scaling
183
+ const finalMouthWidth = baseMouthWidth * mouthSizeScale;
184
+ const finalMouthHeight = baseMouthHeight * mouthSizeScale;
156
185
  const headBaseTransform = this.applyTransform(rootTransform, {
157
186
  x: headPivot.x || 0,
158
187
  y: headPivot.y || 0,
@@ -160,24 +189,37 @@ export class CharacterRigRenderer {
160
189
  scaleX: flipHead ? -1 : 1,
161
190
  scaleY: 1
162
191
  });
163
- const offsetX = Number.isFinite(mouthOffset.x) ? mouthOffset.x : 0;
164
- const offsetY = Number.isFinite(mouthOffset.y) ? mouthOffset.y : 0;
192
+ // Position mouth using the determined offsets (xCoor/yCoor take priority)
193
+ // Note: Anchor point (0.5, 0.5) automatically centers the image at this position
165
194
  const mouthTransform = this.applyTransform(headBaseTransform, {
166
- x: offsetX,
167
- y: offsetY - mouthHeight / 2,
195
+ x: mouthXOffset,
196
+ y: mouthYOffset,
168
197
  rotation: selfRot,
169
198
  scaleX: 1,
170
199
  scaleY: 1
171
200
  });
172
- // CRITICAL FIX: Look up image by ACTUAL PATH from rigData
173
- const mouthImagePath = rigData.imagePaths?.mouth;
174
- const mouthImage = mouthImagePath ? loadedImages[mouthImagePath] : undefined;
201
+ // Get current mouth shape and look up the corresponding image
202
+ // If currentMouthShape is specified, use it to look up the specific mouth image
203
+ // Otherwise, fall back to the static imagePaths.mouth
204
+ let mouthImagePath;
205
+ let mouthImage;
206
+ const currentMouthShape = rigData.currentMouthShape;
207
+ if (currentMouthShape && rigData.mouth && rigData.mouth[currentMouthShape]) {
208
+ // Use the specific mouth shape image from rigData.mouth[shape]
209
+ mouthImagePath = rigData.mouth[currentMouthShape];
210
+ mouthImage = mouthImagePath ? loadedImages[mouthImagePath] : undefined;
211
+ }
212
+ else {
213
+ // Fallback to static imagePaths.mouth
214
+ mouthImagePath = rigData.imagePaths?.mouth;
215
+ mouthImage = mouthImagePath ? loadedImages[mouthImagePath] : undefined;
216
+ }
175
217
  allObjects.push({
176
218
  name: 'mouth',
177
219
  type: 'limb',
178
220
  zIndex: zIndexValues['mouth'] || 1,
179
- width: mouthWidth * imageScale,
180
- height: mouthHeight * imageScale,
221
+ width: finalMouthWidth * imageScale,
222
+ height: finalMouthHeight * imageScale,
181
223
  x: mouthTransform.x,
182
224
  y: mouthTransform.y,
183
225
  rotation: mouthTransform.rotation,
@@ -290,8 +332,25 @@ export class CharacterRigRenderer {
290
332
  scaleX: flipHead ? -1 : 1,
291
333
  scaleY: 1
292
334
  });
293
- const offsetX = Number.isFinite(eyes.leftIrisXCoor) ? eyes.leftIrisXCoor : -10;
294
- const offsetY = Number.isFinite(eyes.leftIrisYCoor) ? eyes.leftIrisYCoor : -5;
335
+ // Base iris position from rig data
336
+ let offsetX = Number.isFinite(eyes.leftIrisXCoor) ? eyes.leftIrisXCoor : -10;
337
+ let offsetY = Number.isFinite(eyes.leftIrisYCoor) ? eyes.leftIrisYCoor : -5;
338
+ // Apply manual eye positioning if eyePositions exists
339
+ const eyePositions = eyes.eyePositions;
340
+ if (eyePositions?.left) {
341
+ const eyePos = eyePositions.left;
342
+ const hasEyeMovement = eyePos.x !== undefined && eyePos.y !== undefined &&
343
+ (eyePos.x !== 0 || eyePos.y !== 0);
344
+ if (hasEyeMovement) {
345
+ // eyePos values are in -2 to 2 range
346
+ // Scale them to pixel movement (matching the old Body.js behavior)
347
+ const movementScale = 5; // Pixels of movement per unit
348
+ const deltaX = eyePos.x * movementScale;
349
+ const deltaY = eyePos.y * movementScale;
350
+ offsetX += deltaX;
351
+ offsetY += deltaY;
352
+ }
353
+ }
295
354
  const baseLeftIrisWidth = eyes.leftIrisWidth || 10;
296
355
  const baseLeftIrisHeight = eyes.leftIrisHeight || 10;
297
356
  const leftIrisWidth = baseLeftIrisWidth * (eyes.leftIrisWidthRatio || 1.0);
@@ -333,8 +392,25 @@ export class CharacterRigRenderer {
333
392
  scaleX: flipHead ? -1 : 1,
334
393
  scaleY: 1
335
394
  });
336
- const offsetX = Number.isFinite(eyes.rightIrisXCoor) ? eyes.rightIrisXCoor : 10;
337
- const offsetY = Number.isFinite(eyes.rightIrisYCoor) ? eyes.rightIrisYCoor : -5;
395
+ // Base iris position from rig data
396
+ let offsetX = Number.isFinite(eyes.rightIrisXCoor) ? eyes.rightIrisXCoor : 10;
397
+ let offsetY = Number.isFinite(eyes.rightIrisYCoor) ? eyes.rightIrisYCoor : -5;
398
+ // Apply manual eye positioning if eyePositions exists
399
+ const eyePositions = eyes.eyePositions;
400
+ if (eyePositions?.right) {
401
+ const eyePos = eyePositions.right;
402
+ const hasEyeMovement = eyePos.x !== undefined && eyePos.y !== undefined &&
403
+ (eyePos.x !== 0 || eyePos.y !== 0);
404
+ if (hasEyeMovement) {
405
+ // eyePos values are in -2 to 2 range
406
+ // Scale them to pixel movement (matching the old Body.js behavior)
407
+ const movementScale = 5; // Pixels of movement per unit
408
+ const deltaX = eyePos.x * movementScale;
409
+ const deltaY = eyePos.y * movementScale;
410
+ offsetX += deltaX;
411
+ offsetY += deltaY;
412
+ }
413
+ }
338
414
  const baseRightIrisWidth = eyes.rightIrisWidth || 10;
339
415
  const baseRightIrisHeight = eyes.rightIrisHeight || 10;
340
416
  const rightIrisWidth = baseRightIrisWidth * (eyes.rightIrisWidthRatio || 1.0);