File size: 1,568 Bytes
26753ca 99e34b4 26753ca 99e34b4 26753ca | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | 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));
},
};
}
|