@pollen-robotics/reachy-mini-sdk 1.8.0 → 1.8.1

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 (67) hide show
  1. package/APP_CREATION_GUIDE.md +1795 -0
  2. package/README.md +2 -5
  3. package/dist/animation/distance.d.ts +87 -0
  4. package/dist/animation/distance.d.ts.map +1 -0
  5. package/dist/animation/distance.js +140 -0
  6. package/dist/animation/distance.js.map +1 -0
  7. package/dist/animation/index.d.ts +34 -0
  8. package/dist/animation/index.d.ts.map +1 -0
  9. package/dist/animation/index.js +33 -0
  10. package/dist/animation/index.js.map +1 -0
  11. package/dist/animation/pose.d.ts +40 -0
  12. package/dist/animation/pose.d.ts.map +1 -0
  13. package/dist/animation/pose.js +15 -0
  14. package/dist/animation/pose.js.map +1 -0
  15. package/dist/animation/presets.d.ts +85 -0
  16. package/dist/animation/presets.d.ts.map +1 -0
  17. package/dist/animation/presets.js +82 -0
  18. package/dist/animation/presets.js.map +1 -0
  19. package/dist/animation/safe-return.d.ts +90 -0
  20. package/dist/animation/safe-return.d.ts.map +1 -0
  21. package/dist/animation/safe-return.js +123 -0
  22. package/dist/animation/safe-return.js.map +1 -0
  23. package/dist/lib/reachy-mini.d.ts +99 -0
  24. package/dist/lib/reachy-mini.d.ts.map +1 -1
  25. package/dist/lib/reachy-mini.js +314 -9
  26. package/dist/lib/reachy-mini.js.map +1 -1
  27. package/dist/lib/types.d.ts +27 -0
  28. package/dist/lib/types.d.ts.map +1 -1
  29. package/host/README.md +14 -12
  30. package/host/dist/ReachyHost.d.ts +2 -1
  31. package/host/dist/ReachyHost.d.ts.map +1 -1
  32. package/host/dist/chunks/index-lMs2sCXG.js +439 -0
  33. package/host/dist/chunks/{mountHost-D7cgkU9Q.js → mountHost-DjE5zE9R.js} +11142 -11014
  34. package/host/dist/chunks/{reachy-mini-B1hlBmDQ.js → reachy-mini-GHNS4GSp.js} +494 -307
  35. package/host/dist/components/PickerView.d.ts.map +1 -1
  36. package/host/dist/components/PostOAuthSplash.d.ts +25 -0
  37. package/host/dist/components/PostOAuthSplash.d.ts.map +1 -0
  38. package/host/dist/components/ReachyHostShell.d.ts.map +1 -1
  39. package/host/dist/components/TopBar.d.ts +8 -1
  40. package/host/dist/components/TopBar.d.ts.map +1 -1
  41. package/host/dist/components/WelcomeBackOverlay.d.ts.map +1 -1
  42. package/host/dist/embed/index.d.ts +3 -2
  43. package/host/dist/embed/index.d.ts.map +1 -1
  44. package/host/dist/entry/auto.js +2 -2
  45. package/host/dist/entry/embed.js +2 -2
  46. package/host/dist/hooks/useHostBridge.d.ts +6 -0
  47. package/host/dist/hooks/useHostBridge.d.ts.map +1 -1
  48. package/host/dist/hooks/useSdk.d.ts.map +1 -1
  49. package/host/dist/index.js +3 -3
  50. package/host/dist/lib/protocol.d.ts +17 -3
  51. package/host/dist/lib/protocol.d.ts.map +1 -1
  52. package/host/dist/lib/settings.d.ts +3 -2
  53. package/host/dist/lib/settings.d.ts.map +1 -1
  54. package/host/dist/mountHost.d.ts.map +1 -1
  55. package/host/dist/ui/design/IdentityChipBar.d.ts +46 -0
  56. package/host/dist/ui/design/IdentityChipBar.d.ts.map +1 -0
  57. package/host/dist/ui/design/LinkQualityBars.d.ts +32 -0
  58. package/host/dist/ui/design/LinkQualityBars.d.ts.map +1 -0
  59. package/host/dist/ui/design/MetaPill.d.ts +41 -0
  60. package/host/dist/ui/design/MetaPill.d.ts.map +1 -0
  61. package/host/dist/ui/design/TransportChip.d.ts +39 -0
  62. package/host/dist/ui/design/TransportChip.d.ts.map +1 -0
  63. package/package.json +7 -4
  64. package/CHANGELOG.md +0 -188
  65. package/host/APP_AUTHOR_GUIDE.md +0 -646
  66. package/host/SPEC.md +0 -618
  67. package/host/dist/chunks/index-CyLPysJS.js +0 -400
package/README.md CHANGED
@@ -98,9 +98,8 @@ See the JSDoc header in [`reachy-mini-sdk.js`](./reachy-mini-sdk.js) for the ful
98
98
 
99
99
  For Hugging Face Spaces apps that need OAuth + a robot picker + iframe lifecycle management:
100
100
 
101
- - [`host/README.md`](./host/README.md) — quickstart and integration overview
102
- - [`host/APP_AUTHOR_GUIDE.md`](./host/APP_AUTHOR_GUIDE.md) — full guide for app authors
103
- - [`host/SPEC.md`](./host/SPEC.md) — host ↔ embed protocol spec
101
+ - **[`APP_CREATION_GUIDE.md`](./APP_CREATION_GUIDE.md)**single source of truth for app authors (scaffold, `sdk: static` deploy, host ↔ embed contract, invariants). Today's SDK pin: `1.8.0`.
102
+ - [`host/README.md`](./host/README.md) — one-page tour of the host package layout
104
103
 
105
104
  ## Migration from `@pollen-robotics/reachy-mini-host`
106
105
 
@@ -122,8 +121,6 @@ You can drop `@pollen-robotics/reachy-mini-host` from your `package.json`. The h
122
121
 
123
122
  The host bundles now import the SDK directly and assign it on `window.ReachyMini` at load time, so apps no longer need a second `<script type="module">` for the SDK alone.
124
123
 
125
- See the [CHANGELOG](./CHANGELOG.md) for the full release history.
126
-
127
124
  ## License
128
125
 
129
126
  Apache-2.0 — see [LICENSE](./LICENSE).
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Pose distance + scaled duration math.
3
+ *
4
+ * Pure functions, no SDK calls, no clock reads. The caller passes a
5
+ * `current` pose (typically from `reachy.robotState`) and a `target`
6
+ * pose; the helpers return per-channel distances and a "feels right"
7
+ * duration for `gotoTarget`.
8
+ *
9
+ * Mirror of the daemon's `utils/interpolation.distance_between_poses`
10
+ * (head magic-mm) + the scaled-duration algorithm used internally for
11
+ * `wake_up` / `goto_sleep`. Duplicated client-side so apps know the
12
+ * duration **synchronously** for audio sync, streamer scheduling, and
13
+ * live constant tuning.
14
+ */
15
+ import type { PartialPose } from "./pose.js";
16
+ import { type ScaledDurationPreset } from "./presets.js";
17
+ /**
18
+ * Per-channel "raw" distance between two poses.
19
+ *
20
+ * Channels missing from either input are absent from the result (the
21
+ * caller's `current` and `target` may both be `PartialPose`).
22
+ *
23
+ * Units:
24
+ * - `head`: "magic-mm" — translation_mm + rotation_deg fused into one
25
+ * scalar. The Python SDK's `utils/interpolation.distance_between_poses`
26
+ * uses the same trick: two unrelated units summed into a single
27
+ * number that's monotonic with "how big does this motion feel".
28
+ * - `antennas.right` / `antennas.left`: `|Δ°|` per antenna.
29
+ * - `body_yaw`: `|Δ°|`.
30
+ *
31
+ * Useful in log lines:
32
+ * `head=3.2mm, antennaR=18°, body=14°, limiter=antennaR`
33
+ */
34
+ export interface PoseDistance {
35
+ head?: number;
36
+ antennas?: {
37
+ right: number;
38
+ left: number;
39
+ };
40
+ body_yaw?: number;
41
+ }
42
+ /**
43
+ * Compute the per-channel distance between two poses.
44
+ *
45
+ * Pure function. Allocates only the output object.
46
+ */
47
+ export declare function distanceBetweenPoses(current: PartialPose, target: PartialPose): PoseDistance;
48
+ /** Outcome of a scaled-duration calculation. */
49
+ export interface ScaledDurationResult {
50
+ /** Duration to pass to `gotoTarget`, clamped to the preset (sec). */
51
+ readonly duration: number;
52
+ /** Which channel was the slowest (i.e. dictated the duration).
53
+ * `null` when `current` and `target` had no overlapping channels. */
54
+ readonly limiter: "head" | "antennaR" | "antennaL" | "body_yaw" | null;
55
+ /** Per-channel un-clamped candidate durations (sec), for log lines
56
+ * and "why is this slow?" diagnostics. */
57
+ readonly perChannel: Readonly<{
58
+ head?: number;
59
+ antennaR?: number;
60
+ antennaL?: number;
61
+ body_yaw?: number;
62
+ }>;
63
+ }
64
+ /**
65
+ * Pick a `goto` duration that "feels right" for the move from
66
+ * `current` to `target`.
67
+ *
68
+ * Algorithm: for each channel defined on both sides, compute its
69
+ * candidate duration as `channelDistance × channelCost`. Take the max
70
+ * (slowest channel limits). Clamp to
71
+ * `[preset.minDurationSec, preset.maxDurationSec]`.
72
+ *
73
+ * If no channel overlaps, returns `{ duration: minDurationSec,
74
+ * limiter: null, perChannel: {} }` — a safe fallback the caller can
75
+ * still pass to `gotoTarget` (the resulting move is a no-op held over
76
+ * the min duration).
77
+ *
78
+ * **Divergence from Rémi's `reachy-mini-js-practices` bench (intentional):**
79
+ * his version returns `max` in the no-overlap case. We return `min`
80
+ * instead — a no-op move doesn't need the maximum dwell time, and the
81
+ * minimum is the smallest legal duration the daemon accepts. Callers
82
+ * that need a longer dwell can pass an explicit duration.
83
+ *
84
+ * Pure function. No SDK reads, no clock reads.
85
+ */
86
+ export declare function scaledDuration(current: PartialPose, target: PartialPose, preset?: ScaledDurationPreset): ScaledDurationResult;
87
+ //# sourceMappingURL=distance.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distance.d.ts","sourceRoot":"","sources":["../../animation/distance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAEH,KAAK,oBAAoB,EAC5B,MAAM,cAAc,CAAC;AAItB;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,YAAY;IACzB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAChC,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,WAAW,GACpB,YAAY,CA0Bd;AAgDD,gDAAgD;AAChD,MAAM,WAAW,oBAAoB;IACjC,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B;0EACsE;IACtE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,GAAG,UAAU,GAAG,UAAU,GAAG,IAAI,CAAC;IACvE;+CAC2C;IAC3C,QAAQ,CAAC,UAAU,EAAE,QAAQ,CAAC;QAC1B,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACrB,CAAC,CAAC;CACN;AAED;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,cAAc,CAC1B,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,WAAW,EACnB,MAAM,GAAE,oBAAqD,GAC9D,oBAAoB,CAwCtB"}
@@ -0,0 +1,140 @@
1
+ /**
2
+ * Pose distance + scaled duration math.
3
+ *
4
+ * Pure functions, no SDK calls, no clock reads. The caller passes a
5
+ * `current` pose (typically from `reachy.robotState`) and a `target`
6
+ * pose; the helpers return per-channel distances and a "feels right"
7
+ * duration for `gotoTarget`.
8
+ *
9
+ * Mirror of the daemon's `utils/interpolation.distance_between_poses`
10
+ * (head magic-mm) + the scaled-duration algorithm used internally for
11
+ * `wake_up` / `goto_sleep`. Duplicated client-side so apps know the
12
+ * duration **synchronously** for audio sync, streamer scheduling, and
13
+ * live constant tuning.
14
+ */
15
+ import { radToDeg } from "../lib/math.js";
16
+ import { DEFAULT_SCALED_DURATION_PRESET, } from "./presets.js";
17
+ /**
18
+ * Compute the per-channel distance between two poses.
19
+ *
20
+ * Pure function. Allocates only the output object.
21
+ */
22
+ export function distanceBetweenPoses(current, target) {
23
+ const out = {};
24
+ if (current.head !== undefined && target.head !== undefined) {
25
+ out.head = headDistanceMagicMm(current.head, target.head);
26
+ }
27
+ if (current.antennas !== undefined && target.antennas !== undefined) {
28
+ const curR = current.antennas[0] ?? 0;
29
+ const curL = current.antennas[1] ?? 0;
30
+ const tgtR = target.antennas[0] ?? 0;
31
+ const tgtL = target.antennas[1] ?? 0;
32
+ out.antennas = {
33
+ right: Math.abs(radToDeg(tgtR - curR)),
34
+ left: Math.abs(radToDeg(tgtL - curL)),
35
+ };
36
+ }
37
+ if (typeof current.body_yaw === "number" &&
38
+ typeof target.body_yaw === "number") {
39
+ out.body_yaw = Math.abs(radToDeg(target.body_yaw - current.body_yaw));
40
+ }
41
+ return out;
42
+ }
43
+ /**
44
+ * Fuse translation (mm) and rotation (deg) of a 4×4 head transform
45
+ * delta into a single "magic-mm" scalar.
46
+ *
47
+ * Mirrors Python `distance_between_poses`:
48
+ * - Translation distance = `|t_a - t_b|` (Euclidean, mm).
49
+ * - Rotation distance = `arccos((trace(R_a^T · R_b) - 1) / 2)` in
50
+ * degrees, robust to numerical drift via clamping.
51
+ * - Magic-mm = `translation_mm + rotation_deg`.
52
+ *
53
+ * Assumes incoming matrices use **metres** for the translation column
54
+ * (indices 3, 7, 11 in row-major), matching the daemon's wire format,
55
+ * and converts to millimetres internally.
56
+ */
57
+ function headDistanceMagicMm(headA, headB) {
58
+ // Translation in metres at indices 3, 7, 11 (row-major).
59
+ const dxM = (headA[3] ?? 0) - (headB[3] ?? 0);
60
+ const dyM = (headA[7] ?? 0) - (headB[7] ?? 0);
61
+ const dzM = (headA[11] ?? 0) - (headB[11] ?? 0);
62
+ const translationMm = Math.sqrt(dxM * dxM + dyM * dyM + dzM * dzM) * 1000;
63
+ // Top-left 3×3 of each, row-major: trace(A^T · B) = Σ_ij A[i,j] * B[i,j]
64
+ const trace = (headA[0] ?? 0) * (headB[0] ?? 0) +
65
+ (headA[1] ?? 0) * (headB[1] ?? 0) +
66
+ (headA[2] ?? 0) * (headB[2] ?? 0) +
67
+ (headA[4] ?? 0) * (headB[4] ?? 0) +
68
+ (headA[5] ?? 0) * (headB[5] ?? 0) +
69
+ (headA[6] ?? 0) * (headB[6] ?? 0) +
70
+ (headA[8] ?? 0) * (headB[8] ?? 0) +
71
+ (headA[9] ?? 0) * (headB[9] ?? 0) +
72
+ (headA[10] ?? 0) * (headB[10] ?? 0);
73
+ // Clamp to [-1, 1] before arccos to absorb floating-point drift
74
+ // (matrices that should be orthonormal sometimes have trace numerically
75
+ // slightly outside the valid range).
76
+ let cosTheta = (trace - 1) / 2;
77
+ if (cosTheta > 1)
78
+ cosTheta = 1;
79
+ else if (cosTheta < -1)
80
+ cosTheta = -1;
81
+ const rotationDeg = radToDeg(Math.acos(cosTheta));
82
+ return translationMm + rotationDeg;
83
+ }
84
+ /**
85
+ * Pick a `goto` duration that "feels right" for the move from
86
+ * `current` to `target`.
87
+ *
88
+ * Algorithm: for each channel defined on both sides, compute its
89
+ * candidate duration as `channelDistance × channelCost`. Take the max
90
+ * (slowest channel limits). Clamp to
91
+ * `[preset.minDurationSec, preset.maxDurationSec]`.
92
+ *
93
+ * If no channel overlaps, returns `{ duration: minDurationSec,
94
+ * limiter: null, perChannel: {} }` — a safe fallback the caller can
95
+ * still pass to `gotoTarget` (the resulting move is a no-op held over
96
+ * the min duration).
97
+ *
98
+ * **Divergence from Rémi's `reachy-mini-js-practices` bench (intentional):**
99
+ * his version returns `max` in the no-overlap case. We return `min`
100
+ * instead — a no-op move doesn't need the maximum dwell time, and the
101
+ * minimum is the smallest legal duration the daemon accepts. Callers
102
+ * that need a longer dwell can pass an explicit duration.
103
+ *
104
+ * Pure function. No SDK reads, no clock reads.
105
+ */
106
+ export function scaledDuration(current, target, preset = DEFAULT_SCALED_DURATION_PRESET) {
107
+ const dist = distanceBetweenPoses(current, target);
108
+ const perChannel = {};
109
+ if (dist.head !== undefined) {
110
+ perChannel.head = dist.head * preset.headSecPerMagicMm;
111
+ }
112
+ if (dist.antennas !== undefined) {
113
+ perChannel.antennaR = dist.antennas.right * preset.antennaSecPerDeg;
114
+ perChannel.antennaL = dist.antennas.left * preset.antennaSecPerDeg;
115
+ }
116
+ if (dist.body_yaw !== undefined) {
117
+ perChannel.body_yaw = dist.body_yaw * preset.bodyYawSecPerDeg;
118
+ }
119
+ let limiter = null;
120
+ // Sentinel: -1 means "no channel seen yet". Distinguishes "no
121
+ // overlap" (limiter stays null) from "overlap but zero motion"
122
+ // (limiter = first overlapping channel, raw = 0).
123
+ let rawDuration = -1;
124
+ for (const key of ["head", "antennaR", "antennaL", "body_yaw"]) {
125
+ const value = perChannel[key];
126
+ if (value === undefined)
127
+ continue;
128
+ if (value > rawDuration) {
129
+ rawDuration = value;
130
+ limiter = key;
131
+ }
132
+ }
133
+ let duration = rawDuration < 0 ? 0 : rawDuration;
134
+ if (duration < preset.minDurationSec)
135
+ duration = preset.minDurationSec;
136
+ if (duration > preset.maxDurationSec)
137
+ duration = preset.maxDurationSec;
138
+ return { duration, limiter, perChannel };
139
+ }
140
+ //# sourceMappingURL=distance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distance.js","sourceRoot":"","sources":["../../animation/distance.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * `@pollen-robotics/reachy-mini-sdk/animation` — motion utilities.
3
+ *
4
+ * Phase 1 surface, split by concern:
5
+ *
6
+ * - **Types** (`Pose`, `PartialPose`): the wire format every SDK
7
+ * motion call already uses.
8
+ * - **Canonical pose** (`INIT_POSE` + sub-constants): the "safe
9
+ * rest" pose, mirror of the daemon's `Backend.INIT_HEAD_POSE` +
10
+ * `Backend.INIT_ANTENNAS_JOINT_POSITIONS`.
11
+ * - **Distance math** (`distanceBetweenPoses`, `scaledDuration`):
12
+ * "how big is this move" + "how long should it take", computed
13
+ * synchronously client-side so apps can sync audio / scheduling
14
+ * against it.
15
+ * - **Exit handlers** (`safelyReturnToPose`, `installShutdownHandler`):
16
+ * thin convenience wrappers around the three-call SDK sequence
17
+ * (`setMotorMode` + read state + `gotoTarget`) for `pagehide` /
18
+ * `onLeave` call sites.
19
+ *
20
+ * Pure-TS: this lib does not introduce any daemon-side primitive. All
21
+ * motion routes through existing data-channel commands. See
22
+ * `DESIGN.md` for the rationale.
23
+ *
24
+ * @see DESIGN.md
25
+ * @see APP_CREATION_GUIDE.md — "Robotics best practices" section
26
+ */
27
+ export type { Pose, PartialPose } from "./pose.js";
28
+ export type { PoseDistance, ScaledDurationResult } from "./distance.js";
29
+ export type { ScaledDurationPreset } from "./presets.js";
30
+ export type { SafelyReturnOptions, InstallShutdownHandlerOptions, } from "./safe-return.js";
31
+ export { INIT_HEAD_POSE_FLAT, INIT_ANTENNAS_RAD, INIT_BODY_YAW_RAD, INIT_POSE, DEFAULT_SCALED_DURATION_PRESET, } from "./presets.js";
32
+ export { distanceBetweenPoses, scaledDuration } from "./distance.js";
33
+ export { safelyReturnToPose, installShutdownHandler } from "./safe-return.js";
34
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../animation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAGH,YAAY,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AACnD,YAAY,EAAE,YAAY,EAAE,oBAAoB,EAAE,MAAM,eAAe,CAAC;AACxE,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AACzD,YAAY,EACR,mBAAmB,EACnB,6BAA6B,GAChC,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACH,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,SAAS,EACT,8BAA8B,GACjC,MAAM,cAAc,CAAC;AAGtB,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAGrE,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,33 @@
1
+ /**
2
+ * `@pollen-robotics/reachy-mini-sdk/animation` — motion utilities.
3
+ *
4
+ * Phase 1 surface, split by concern:
5
+ *
6
+ * - **Types** (`Pose`, `PartialPose`): the wire format every SDK
7
+ * motion call already uses.
8
+ * - **Canonical pose** (`INIT_POSE` + sub-constants): the "safe
9
+ * rest" pose, mirror of the daemon's `Backend.INIT_HEAD_POSE` +
10
+ * `Backend.INIT_ANTENNAS_JOINT_POSITIONS`.
11
+ * - **Distance math** (`distanceBetweenPoses`, `scaledDuration`):
12
+ * "how big is this move" + "how long should it take", computed
13
+ * synchronously client-side so apps can sync audio / scheduling
14
+ * against it.
15
+ * - **Exit handlers** (`safelyReturnToPose`, `installShutdownHandler`):
16
+ * thin convenience wrappers around the three-call SDK sequence
17
+ * (`setMotorMode` + read state + `gotoTarget`) for `pagehide` /
18
+ * `onLeave` call sites.
19
+ *
20
+ * Pure-TS: this lib does not introduce any daemon-side primitive. All
21
+ * motion routes through existing data-channel commands. See
22
+ * `DESIGN.md` for the rationale.
23
+ *
24
+ * @see DESIGN.md
25
+ * @see APP_CREATION_GUIDE.md — "Robotics best practices" section
26
+ */
27
+ // Constants
28
+ export { INIT_HEAD_POSE_FLAT, INIT_ANTENNAS_RAD, INIT_BODY_YAW_RAD, INIT_POSE, DEFAULT_SCALED_DURATION_PRESET, } from "./presets.js";
29
+ // Distance + scaled duration
30
+ export { distanceBetweenPoses, scaledDuration } from "./distance.js";
31
+ // Exit-handler helpers
32
+ export { safelyReturnToPose, installShutdownHandler } from "./safe-return.js";
33
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../animation/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAWH,YAAY;AACZ,OAAO,EACH,mBAAmB,EACnB,iBAAiB,EACjB,iBAAiB,EACjB,SAAS,EACT,8BAA8B,GACjC,MAAM,cAAc,CAAC;AAEtB,6BAA6B;AAC7B,OAAO,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAErE,uBAAuB;AACvB,OAAO,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Pose primitives.
3
+ *
4
+ * A `Pose` is the canonical "frame" the SDK sends and receives on the
5
+ * data channel. The shape mirrors `setTarget` / `gotoTarget` / the
6
+ * `state` event payload, named so it can be passed around without
7
+ * anonymous-object soup.
8
+ *
9
+ * Channel units (wire format):
10
+ * - `head` : flat 16-float row-major 4×4 homogeneous matrix.
11
+ * - `antennas` : [right, left] in **radians**.
12
+ * - `body_yaw` : scalar in **radians**.
13
+ */
14
+ /**
15
+ * Canonical pose carried over the data channel. All three channels
16
+ * required.
17
+ */
18
+ export interface Pose {
19
+ /** Flat 16-float row-major 4×4 head pose. */
20
+ head: number[];
21
+ /** [right, left] in radians. */
22
+ antennas: [number, number];
23
+ /** Body yaw in radians. */
24
+ body_yaw: number;
25
+ }
26
+ /**
27
+ * Same shape as `Pose` but every channel is optional. Matches the
28
+ * partial-update semantics of `setTarget` / `gotoTarget`: only the
29
+ * channels you specify are commanded; the rest keep their previous
30
+ * target.
31
+ *
32
+ * Also the shape `reachy.robotState` actually carries — fields appear
33
+ * only once the daemon has emitted them.
34
+ */
35
+ export interface PartialPose {
36
+ head?: number[];
37
+ antennas?: [number, number] | number[];
38
+ body_yaw?: number;
39
+ }
40
+ //# sourceMappingURL=pose.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pose.d.ts","sourceRoot":"","sources":["../../animation/pose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;GAGG;AACH,MAAM,WAAW,IAAI;IACjB,6CAA6C;IAC7C,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,gCAAgC;IAChC,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,2BAA2B;IAC3B,QAAQ,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW;IACxB,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Pose primitives.
3
+ *
4
+ * A `Pose` is the canonical "frame" the SDK sends and receives on the
5
+ * data channel. The shape mirrors `setTarget` / `gotoTarget` / the
6
+ * `state` event payload, named so it can be passed around without
7
+ * anonymous-object soup.
8
+ *
9
+ * Channel units (wire format):
10
+ * - `head` : flat 16-float row-major 4×4 homogeneous matrix.
11
+ * - `antennas` : [right, left] in **radians**.
12
+ * - `body_yaw` : scalar in **radians**.
13
+ */
14
+ export {};
15
+ //# sourceMappingURL=pose.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pose.js","sourceRoot":"","sources":["../../animation/pose.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * Canonical safe-rest pose + scaled-duration preset.
3
+ *
4
+ * Both are mirrored from the daemon (Python). The constants live on
5
+ * both sides because apps need the values **synchronously** in JS:
6
+ *
7
+ * - `INIT_POSE`: the "home" pose for `safelyReturnToPose`'s default
8
+ * target. Mirror of `Backend.INIT_HEAD_POSE` + `Backend.INIT_ANTENNAS_JOINT_POSITIONS`
9
+ * in `src/reachy_mini/daemon/backend/abstract.py`.
10
+ * - `DEFAULT_SCALED_DURATION_PRESET`: the per-channel "magic-mm × cost"
11
+ * tuning. Mirror of the constants the daemon already uses for
12
+ * `wake_up()` / `goto_sleep()` durations.
13
+ *
14
+ * **If you change a value here**, update the matching constant in
15
+ * `src/reachy_mini/daemon/backend/abstract.py` in the same commit.
16
+ */
17
+ import type { Pose } from "./pose.js";
18
+ /**
19
+ * Identity 4×4 head matrix, row-major, flattened.
20
+ *
21
+ * Mirror of `Backend.INIT_HEAD_POSE` (Python `np.eye(4)`) in
22
+ * `abstract.py`. Frozen so apps can't accidentally mutate the shared
23
+ * instance via `INIT_POSE.head[0] = 0`.
24
+ */
25
+ export declare const INIT_HEAD_POSE_FLAT: readonly number[];
26
+ /**
27
+ * Antennas at ~±10° outward (anti-resonance offset).
28
+ *
29
+ * Mirror of `Backend.INIT_ANTENNAS_JOINT_POSITIONS = [-0.1745, 0.1745]`
30
+ * (rounded to match Python bit-for-bit) in `abstract.py`. Background:
31
+ * straight-up (0°, 0°) antennas mechanically resonate with the
32
+ * head-motor cogging frequency; the ~10° symmetric outward tilt damps
33
+ * it. See [PR #952](https://github.com/pollen-robotics/reachy_mini/pull/952).
34
+ */
35
+ export declare const INIT_ANTENNAS_RAD: readonly [number, number];
36
+ /** Body squared up: head and body share the world-frame yaw axis at rest. */
37
+ export declare const INIT_BODY_YAW_RAD: number;
38
+ /**
39
+ * Aggregate canonical "safe rest" pose.
40
+ *
41
+ * Default target for `safelyReturnToPose`. Deep-frozen, so spread it
42
+ * if you need a mutable copy:
43
+ * `{ ...INIT_POSE, head: INIT_POSE.head.slice() }`.
44
+ */
45
+ export declare const INIT_POSE: Readonly<Pose>;
46
+ /**
47
+ * Tuning knobs for `scaledDuration` and friends.
48
+ *
49
+ * Each `*SecPer*` field is the per-unit cost of motion on that channel.
50
+ * A move's duration is `max(channelDistance × channelCost)` across all
51
+ * channels, clamped to `[minDurationSec, maxDurationSec]`. Slowest
52
+ * channel wins.
53
+ */
54
+ export interface ScaledDurationPreset {
55
+ /** Head: `magicMm × this` = head channel candidate (sec). */
56
+ readonly headSecPerMagicMm: number;
57
+ /** Per antenna: `|Δ°| × this` = each antenna's candidate (sec). */
58
+ readonly antennaSecPerDeg: number;
59
+ /** Body yaw: `|Δ°| × this` = body channel candidate (sec). */
60
+ readonly bodyYawSecPerDeg: number;
61
+ /** Lower bound on the final duration (sec). */
62
+ readonly minDurationSec: number;
63
+ /** Upper bound on the final duration (sec). */
64
+ readonly maxDurationSec: number;
65
+ }
66
+ /**
67
+ * Default tuning, calibrated on a real Reachy Mini via the
68
+ * `reachy-mini-js-practices` bench (May 2026).
69
+ *
70
+ * Per-channel rationale:
71
+ * - **head**: 0.015 s per "magic-mm" (translation_mm + rotation_deg).
72
+ * 0.02 reads as noticeably slow on the head.
73
+ * - **antenna**: 0.005 s/°. Antennas are light, but the mechanical
74
+ * resonance window (~PR #952) penalises overly fast moves.
75
+ * - **body_yaw**: 0.015 s/°. Body sits between head (heavy) and
76
+ * antennas (light).
77
+ * - **min/max**: 0.01 / 1.5 s. The low floor matters for in-app
78
+ * interactions — at 0.2 s, every tiny correction takes 200 ms
79
+ * minimum and reads as sluggish.
80
+ *
81
+ * Frozen so apps can't mutate the shared instance. Spread to derive
82
+ * a custom preset: `{ ...DEFAULT_SCALED_DURATION_PRESET, headSecPerMagicMm: 0.03 }`.
83
+ */
84
+ export declare const DEFAULT_SCALED_DURATION_PRESET: Readonly<ScaledDurationPreset>;
85
+ //# sourceMappingURL=presets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../animation/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAItC;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,EAAE,SAAS,MAAM,EAK/C,CAAC;AAEH;;;;;;;;GAQG;AACH,eAAO,MAAM,iBAAiB,EAAE,SAAS,CAAC,MAAM,EAAE,MAAM,CAEzB,CAAC;AAEhC,6EAA6E;AAC7E,eAAO,MAAM,iBAAiB,EAAE,MAAU,CAAC;AAE3C;;;;;;GAMG;AACH,eAAO,MAAM,SAAS,EAAE,QAAQ,CAAC,IAAI,CAInC,CAAC;AAIH;;;;;;;GAOG;AACH,MAAM,WAAW,oBAAoB;IACjC,6DAA6D;IAC7D,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,mEAAmE;IACnE,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,8DAA8D;IAC9D,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,+CAA+C;IAC/C,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;CACnC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,8BAA8B,EAAE,QAAQ,CAAC,oBAAoB,CAMxE,CAAC"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Canonical safe-rest pose + scaled-duration preset.
3
+ *
4
+ * Both are mirrored from the daemon (Python). The constants live on
5
+ * both sides because apps need the values **synchronously** in JS:
6
+ *
7
+ * - `INIT_POSE`: the "home" pose for `safelyReturnToPose`'s default
8
+ * target. Mirror of `Backend.INIT_HEAD_POSE` + `Backend.INIT_ANTENNAS_JOINT_POSITIONS`
9
+ * in `src/reachy_mini/daemon/backend/abstract.py`.
10
+ * - `DEFAULT_SCALED_DURATION_PRESET`: the per-channel "magic-mm × cost"
11
+ * tuning. Mirror of the constants the daemon already uses for
12
+ * `wake_up()` / `goto_sleep()` durations.
13
+ *
14
+ * **If you change a value here**, update the matching constant in
15
+ * `src/reachy_mini/daemon/backend/abstract.py` in the same commit.
16
+ */
17
+ // ─── Canonical safe-rest pose ────────────────────────────────────────────────
18
+ /**
19
+ * Identity 4×4 head matrix, row-major, flattened.
20
+ *
21
+ * Mirror of `Backend.INIT_HEAD_POSE` (Python `np.eye(4)`) in
22
+ * `abstract.py`. Frozen so apps can't accidentally mutate the shared
23
+ * instance via `INIT_POSE.head[0] = 0`.
24
+ */
25
+ export const INIT_HEAD_POSE_FLAT = Object.freeze([
26
+ 1, 0, 0, 0,
27
+ 0, 1, 0, 0,
28
+ 0, 0, 1, 0,
29
+ 0, 0, 0, 1,
30
+ ]);
31
+ /**
32
+ * Antennas at ~±10° outward (anti-resonance offset).
33
+ *
34
+ * Mirror of `Backend.INIT_ANTENNAS_JOINT_POSITIONS = [-0.1745, 0.1745]`
35
+ * (rounded to match Python bit-for-bit) in `abstract.py`. Background:
36
+ * straight-up (0°, 0°) antennas mechanically resonate with the
37
+ * head-motor cogging frequency; the ~10° symmetric outward tilt damps
38
+ * it. See [PR #952](https://github.com/pollen-robotics/reachy_mini/pull/952).
39
+ */
40
+ export const INIT_ANTENNAS_RAD = Object.freeze([
41
+ -0.1745, 0.1745,
42
+ ]);
43
+ /** Body squared up: head and body share the world-frame yaw axis at rest. */
44
+ export const INIT_BODY_YAW_RAD = 0;
45
+ /**
46
+ * Aggregate canonical "safe rest" pose.
47
+ *
48
+ * Default target for `safelyReturnToPose`. Deep-frozen, so spread it
49
+ * if you need a mutable copy:
50
+ * `{ ...INIT_POSE, head: INIT_POSE.head.slice() }`.
51
+ */
52
+ export const INIT_POSE = Object.freeze({
53
+ head: INIT_HEAD_POSE_FLAT,
54
+ antennas: INIT_ANTENNAS_RAD,
55
+ body_yaw: INIT_BODY_YAW_RAD,
56
+ });
57
+ /**
58
+ * Default tuning, calibrated on a real Reachy Mini via the
59
+ * `reachy-mini-js-practices` bench (May 2026).
60
+ *
61
+ * Per-channel rationale:
62
+ * - **head**: 0.015 s per "magic-mm" (translation_mm + rotation_deg).
63
+ * 0.02 reads as noticeably slow on the head.
64
+ * - **antenna**: 0.005 s/°. Antennas are light, but the mechanical
65
+ * resonance window (~PR #952) penalises overly fast moves.
66
+ * - **body_yaw**: 0.015 s/°. Body sits between head (heavy) and
67
+ * antennas (light).
68
+ * - **min/max**: 0.01 / 1.5 s. The low floor matters for in-app
69
+ * interactions — at 0.2 s, every tiny correction takes 200 ms
70
+ * minimum and reads as sluggish.
71
+ *
72
+ * Frozen so apps can't mutate the shared instance. Spread to derive
73
+ * a custom preset: `{ ...DEFAULT_SCALED_DURATION_PRESET, headSecPerMagicMm: 0.03 }`.
74
+ */
75
+ export const DEFAULT_SCALED_DURATION_PRESET = Object.freeze({
76
+ headSecPerMagicMm: 0.015,
77
+ antennaSecPerDeg: 0.005,
78
+ bodyYawSecPerDeg: 0.015,
79
+ minDurationSec: 0.01,
80
+ maxDurationSec: 1.5,
81
+ });
82
+ //# sourceMappingURL=presets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"presets.js","sourceRoot":"","sources":["../../animation/presets.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAIH,gFAAgF;AAEhF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAsB,MAAM,CAAC,MAAM,CAAC;IAChE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACV,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACV,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IACV,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;CACb,CAAC,CAAC;AAEH;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAA8B,MAAM,CAAC,MAAM,CAAC;IACtE,CAAC,MAAM,EAAE,MAAM;CAClB,CAA8B,CAAC;AAEhC,6EAA6E;AAC7E,MAAM,CAAC,MAAM,iBAAiB,GAAW,CAAC,CAAC;AAE3C;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,SAAS,GAAmB,MAAM,CAAC,MAAM,CAAC;IACnD,IAAI,EAAE,mBAAoD;IAC1D,QAAQ,EAAE,iBAAkE;IAC5E,QAAQ,EAAE,iBAAiB;CAC9B,CAAC,CAAC;AAyBH;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,CAAC,MAAM,8BAA8B,GAAmC,MAAM,CAAC,MAAM,CAAC;IACxF,iBAAiB,EAAE,KAAK;IACxB,gBAAgB,EAAE,KAAK;IACvB,gBAAgB,EAAE,KAAK;IACvB,cAAc,EAAE,IAAI;IACpB,cAAc,EAAE,GAAG;CACtB,CAAC,CAAC"}