@fabi-play/motion 0.2.0 → 0.4.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/dist/index.d.ts CHANGED
@@ -241,22 +241,27 @@ export declare function armsCrossed(body: Body$1): boolean;
241
241
  export declare const CROSS: {
242
242
  /** Each wrist at least this far past the midline (between the shoulders)… */
243
243
  readonly past: 0.12;
244
- /** …and no farther than the opposite shoulder plus this. */
245
- readonly pastShoulder: 0.1;
246
- /** Each elbow at least this far from the midline, on its own side. */
247
- readonly elbowOut: 0.35;
248
- /** Wrists between this far above the shoulder line… */
249
- readonly above: 0.35;
244
+ /** …and no farther than the opposite shoulder plus this (a wide X; self-hugs are told apart by the elbows). */
245
+ readonly pastShoulder: 0.5;
246
+ /** Each elbow at least this far from the midline, on its own side (in a self-hug they come in front of the chest). */
247
+ readonly elbowOut: 0.38;
248
+ /**
249
+ * Wrists between this far above the shoulder line (an X up to the chin and mouth; not higher: hands on the head and
250
+ * forearms over the eyes, a child hiding the face, are not it)…
251
+ */
252
+ readonly above: 0.6;
250
253
  /** …and this far below it (mid-chest). */
251
- readonly below: 0.6;
254
+ readonly below: 0.7;
252
255
  /** Each wrist at least this far above its own elbow (the forearm rises)… */
253
- readonly rise: 0.2;
256
+ readonly rise: 0.15;
254
257
  /** …and this far above the other arm's elbow. */
255
- readonly overElbow: 0.15;
258
+ readonly overElbow: 0.1;
256
259
  /** Elbows no higher than this above the shoulder line (arms crossed over the head are not it)… */
257
- readonly elbowAbove: 0.1;
260
+ readonly elbowAbove: 0.15;
258
261
  /** …and no lower than this below the hip line. */
259
262
  readonly elbowBelowHips: 0.3;
263
+ /** The visibility the wrist hidden behind the other needs; the other wrist, elbows and shoulders need the usual 0.5. */
264
+ readonly hiddenWristVisible: 0.25;
260
265
  /** Shoulders at least this wide: facing the camera. */
261
266
  readonly minShoulderWidth: 0.3;
262
267
  /** Shoulder width over torso, to estimate the torso when the hips are out of view. */
@@ -264,13 +269,19 @@ export declare const CROSS: {
264
269
  };
265
270
  /**
266
271
  * Something held for a while: progress 0–1 while active, fires once when full. Brief drop-outs (under graceMs, e.g.
267
- * a frame where the pose model loses a wrist) don't reset it. After firing it is spent (progress 0, never fires) until
268
- * `active` has been false for longer than graceMs, so holding on doesn't fire again.
272
+ * a frame where the pose model loses a wrist) don't reset it, but only active time fills it (the time between two
273
+ * active frames) and a drop-out drains it at half that rate: a real hold with a few lost frames still fills, while scattered
274
+ * active frames (a false reading now and then, an arm swinging across) never add up to one. After firing it is spent (progress 0, never fires) until `active` has been false for longer than
275
+ * graceMs, so holding on doesn't fire again.
269
276
  */
270
277
  export declare class Hold {
271
278
  readonly ms: number;
272
279
  readonly graceMs: number;
273
- private start;
280
+ /** Active time so far, ms. */
281
+ private held;
282
+ /** The time of the last update, and whether it was active: only active-to-active time counts. */
283
+ private last;
284
+ private lastWasActive;
274
285
  private lastActive;
275
286
  private progress;
276
287
  private spent;
package/dist/index.js CHANGED
@@ -342,7 +342,9 @@ function armsCrossed(body) {
342
342
  return crossedIn(skeleton(body));
343
343
  }
344
344
  function crossedIn(s) {
345
- if (!seen(s.leftShoulder, s.rightShoulder, s.leftElbow, s.rightElbow, s.leftWrist, s.rightWrist)) return false;
345
+ if (!seen(s.leftShoulder, s.rightShoulder, s.leftElbow, s.rightElbow)) return false;
346
+ const wv = [s.leftWrist.visibility, s.rightWrist.visibility];
347
+ if (Math.min(...wv) < CROSS.hiddenWristVisible || Math.max(...wv) < VISIBLE) return false;
346
348
  const hipsSeen = seen(s.leftHip, s.rightHip);
347
349
  const t = hipsSeen ? s.torso : s.shoulderWidth / CROSS.shoulderPerTorso;
348
350
  if (s.shoulderWidth < CROSS.minShoulderWidth * t) return false;
@@ -366,56 +368,76 @@ function crossedIn(s) {
366
368
  var CROSS = {
367
369
  /** Each wrist at least this far past the midline (between the shoulders)… */
368
370
  past: 0.12,
369
- /** …and no farther than the opposite shoulder plus this. */
370
- pastShoulder: 0.1,
371
- /** Each elbow at least this far from the midline, on its own side. */
372
- elbowOut: 0.35,
373
- /** Wrists between this far above the shoulder line… */
374
- above: 0.35,
371
+ /** …and no farther than the opposite shoulder plus this (a wide X; self-hugs are told apart by the elbows). */
372
+ pastShoulder: 0.5,
373
+ /** Each elbow at least this far from the midline, on its own side (in a self-hug they come in front of the chest). */
374
+ elbowOut: 0.38,
375
+ /**
376
+ * Wrists between this far above the shoulder line (an X up to the chin and mouth; not higher: hands on the head and
377
+ * forearms over the eyes, a child hiding the face, are not it)…
378
+ */
379
+ above: 0.6,
375
380
  /** …and this far below it (mid-chest). */
376
- below: 0.6,
381
+ below: 0.7,
377
382
  /** Each wrist at least this far above its own elbow (the forearm rises)… */
378
- rise: 0.2,
383
+ rise: 0.15,
379
384
  /** …and this far above the other arm's elbow. */
380
- overElbow: 0.15,
385
+ overElbow: 0.1,
381
386
  /** Elbows no higher than this above the shoulder line (arms crossed over the head are not it)… */
382
- elbowAbove: 0.1,
387
+ elbowAbove: 0.15,
383
388
  /** …and no lower than this below the hip line. */
384
389
  elbowBelowHips: 0.3,
390
+ /** The visibility the wrist hidden behind the other needs; the other wrist, elbows and shoulders need the usual 0.5. */
391
+ hiddenWristVisible: 0.25,
385
392
  /** Shoulders at least this wide: facing the camera. */
386
393
  minShoulderWidth: 0.3,
387
394
  /** Shoulder width over torso, to estimate the torso when the hips are out of view. */
388
395
  shoulderPerTorso: 0.8
389
396
  };
397
+ var HOLD_DRAIN = 0.5;
390
398
  var Hold = class {
391
399
  constructor(ms = 1500, graceMs = 200) {
392
400
  __publicField(this, "ms", ms);
393
401
  __publicField(this, "graceMs", graceMs);
394
- __publicField(this, "start", null);
402
+ /** Active time so far, ms. */
403
+ __publicField(this, "held", 0);
404
+ /** The time of the last update, and whether it was active: only active-to-active time counts. */
405
+ __publicField(this, "last", null);
406
+ __publicField(this, "lastWasActive", false);
395
407
  __publicField(this, "lastActive", -Infinity);
396
408
  __publicField(this, "progress", 0);
397
409
  __publicField(this, "spent", false);
398
410
  }
399
411
  update(active, now) {
412
+ const dt = this.last !== null ? Math.max(now - this.last, 0) : 0;
413
+ const step = active && this.lastWasActive ? dt : 0;
414
+ this.last = now;
415
+ this.lastWasActive = active;
400
416
  if (active) this.lastActive = now;
401
417
  const released = !active && now - this.lastActive > this.graceMs;
402
418
  if (released) {
403
- this.start = null;
419
+ this.held = 0;
404
420
  this.progress = 0;
405
421
  this.spent = false;
406
422
  return { progress: 0, fired: false };
407
423
  }
408
424
  if (this.spent) return { progress: 0, fired: false };
409
- if (!active) return { progress: this.progress, fired: false };
410
- this.start ?? (this.start = now);
411
- this.progress = Math.min(Math.max((now - this.start) / this.ms, 0), 1);
425
+ if (!active) {
426
+ this.held = Math.max(this.held - dt * HOLD_DRAIN, 0);
427
+ this.progress = this.held / this.ms;
428
+ return { progress: this.progress, fired: false };
429
+ }
430
+ this.held += step;
431
+ this.progress = Math.min(this.held / this.ms, 1);
412
432
  if (this.progress < 1) return { progress: this.progress, fired: false };
413
433
  this.spent = true;
414
434
  this.progress = 0;
415
435
  return { progress: 1, fired: true };
416
436
  }
417
437
  reset() {
418
- this.start = null;
438
+ this.held = 0;
439
+ this.last = null;
440
+ this.lastWasActive = false;
419
441
  this.lastActive = -Infinity;
420
442
  this.progress = 0;
421
443
  this.spent = false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fabi-play/motion",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Body movements from pose landmarks: jumps, squats, shapes, lanes, freezing, hands as pointers.",
5
5
  "keywords": [
6
6
  "fabi-play",
@@ -32,7 +32,7 @@
32
32
  "access": "public"
33
33
  },
34
34
  "dependencies": {
35
- "@fabi-play/protocol": "^0.2.0"
35
+ "@fabi-play/protocol": "^0.4.0"
36
36
  },
37
37
  "devDependencies": {
38
38
  "dts-bundle-generator": "9.5.1",