import { Matrix4 } from "three"; import { interpolateTarget } from "../reachy/reachyKinematics.js"; export const EMOTIONS = Object.freeze({ joy: { sentence: "Oh, you're happy! Me too!", motion: "cheerful1" }, sadness: { sentence: "Oh, you're sad! Me too!", motion: "sad1" }, // Reprimand is the official library's angry gesture with a clear head // shake; keep the more extreme furious1 recording available in the assets. anger: { sentence: "Oh, you're angry! Me too!", motion: "reprimand2" }, }); const matrixFromRows = (rows) => new Matrix4().set(...rows.flat()); export async function loadReachyEmotion(name) { const response = await fetch(`./robot/reachy/emotions/${name}.json`); if (!response.ok) throw new Error(`Unable to load Reachy emotion ${name}`); const source = await response.json(); const frames = source.time.map((time, i) => { const frame = source.set_target_data[i]; return { time, target: { head: matrixFromRows(frame.head), antennas: [...frame.antennas], bodyYaw: frame.body_yaw } }; }); const duration = frames.at(-1)?.time ?? 0; return { duration, sample(seconds) { if (!frames.length) throw new Error(`Empty Reachy emotion ${name}`); if (seconds <= frames[0].time) return frames[0].target; if (seconds >= duration) return frames.at(-1).target; let hi = 1; while (hi < frames.length && frames[hi].time < seconds) hi++; const a = frames[hi - 1], b = frames[hi]; return interpolateTarget(a.target, b.target, (seconds - a.time) / (b.time - a.time)); }, }; }