@rig-c/pose 0.40.0 → 0.42.0

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/src/switch.ts CHANGED
@@ -476,8 +476,15 @@ function moveBoundaries(vals: ReadonlyArray<AlternateSet | null>, pos: readonly
476
476
  return moves;
477
477
  }
478
478
 
479
- /** The key time for a change that shows on frame i: half a frame before it, 0 on the first frame. */
480
- const changeAt = (times: readonly number[], i: number): number => (i === 0 ? 0 : r6((times[i - 1]! + times[i]!) / 2));
479
+ /**
480
+ * The key time for a stepped change that shows on frame i: half a frame before it, 0 on the first frame. A key
481
+ * exactly on a frame time is a tie the render breaks either way (its track time is a running sum of 1/fps, key
482
+ * times are held as float32, and a key applies when its time ≤ the track time), so about half such keys land a
483
+ * frame late (rig-c/pose#325); the midpoint sits half a frame from both ties. Every discrete key pose writes goes
484
+ * through it: the attachment and offset keys here, the draw-order keys in `draworder.ts`, and the face and body yaw
485
+ * sets' attachment keys in `retarget.ts` (rig-c/pose#334).
486
+ */
487
+ export const keyAtFrame = (times: readonly number[], i: number): number => (i === 0 ? 0 : r6((times[i - 1]! + times[i]!) / 2));
481
488
 
482
489
  function keyHandOffset(a: AlternateSet, map: JointMap, cn: string): [number, number] | null {
483
490
  const c = map.chains.find((x) => x.name === cn);
@@ -1116,7 +1123,7 @@ export function selectSwitches(map: JointMap, targets: ReadonlyMap<string, reado
1116
1123
  const keys: AttachmentKey[] = [];
1117
1124
  row.forEach((v, i) => {
1118
1125
  if (v === prev) return;
1119
- keys.push({ t: changeAt(times, i), v });
1126
+ keys.push({ t: keyAtFrame(times, i), v });
1120
1127
  prev = v;
1121
1128
  });
1122
1129
  if (keys.length > 0) slotTracks.push({ slot: s, property: 'attachment', keys });
@@ -1129,7 +1136,7 @@ export function selectSwitches(map: JointMap, targets: ReadonlyMap<string, reado
1129
1136
  row.forEach((v, i) => {
1130
1137
  const prev = row[i - 1];
1131
1138
  if (i === 0 || (prev![0] === v[0] && prev![1] === v[1])) return;
1132
- keys.push({ t: changeAt(times, i), v: [r3(v[0]), r3(v[1])] });
1139
+ keys.push({ t: keyAtFrame(times, i), v: [r3(v[0]), r3(v[1])] });
1133
1140
  });
1134
1141
  // Every key but the last holds until the next (a stepped curve on the last has nothing to ease to).
1135
1142
  for (let k = 0; k + 1 < keys.length; k++) keys[k]!.ease = 'stepped';