import { useState } from "react"; import { gameApi, useGame } from "../store.js"; import { HOME } from "../game/reachy/reachyKinematics.js"; import { POSES, SEQUENCES } from "../game/reachy/reachyMoves.js"; import SimulatorPanel from "./SimulatorPanel.jsx"; const FIELDS = [ ["x", "x (mm)", -20, 20], ["y", "y (mm)", -20, 20], ["z", "z (mm)", -30, 20], ["roll", "Roll (°)", -25, 25], ["pitch", "Pitch (°)", -25, 25], ["yaw", "Yaw (°)", -45, 45], ["leftAntenna", "Left antenna (°)", -90, 90], ["rightAntenna", "Right antenna (°)", -90, 90], ]; export default function ReachyControls() { const [pose, setPose] = useState({ ...HOME }); const [duration, setDuration] = useState(1); const [error, setError] = useState(null); const reachy = useGame((s) => s.reachy); const locked = useGame((s) => s.emotionBusy || s.scriptPlaying); const recording = useGame((s) => s.scriptRecording); const [speech, setSpeech] = useState(""); const act = async (fn) => { setError(null); try { await fn(gameApi.reachy); } catch (e) { if (e.name !== "AbortError") setError(e.message); } }; const action = (label, fn) => recording ? gameApi.script?.add(label, () => act(fn)) : act(fn); return
Poses
{Object.entries(POSES).map(([name, p]) => )}
Sequences
{Object.entries(SEQUENCES).map(([name, sequence]) => )}
Emotions
{[["joy", "Happy"], ["sadness", "Sad"], ["anger", "Angry"]].map(([id, label]) => )}
Custom pose {FIELDS.map(([key, label, min, max]) => )}
Text to speech setSpeech(e.target.value)} />

{reachy.playing ? "Playing · " : ""}{reachy.queue.length} queued

{reachy.queue.length > 0 &&
    {reachy.queue.map((label, i) =>
  1. {label}
  2. )}
} {(error || reachy.error) &&

{error || reachy.error}

}
; }