SimpleDances / plan.txt
RemiFabre
Initial commit
b358f52
Plan for SimpleDances reachy mini app (v1)
=========================================
0. Context & goals
------------------
- Reuse the structure of `reachy_mini_radio` to build a Reachy Mini app with a custom UI hosted from `SimpleDances/SimpleDances/static`.
- Drive actual motions using `reachy_mini_dances_library`, exposing *all* available moves with tunable parameters.
- Provide a clean web UI with dance selection, parameter sliders + numeric inputs, start/stop toggle, BPM + amplitude sliders, reset-to-default per dance, and a rhythmic visualization tied to all 8 DoF (6 head + 2 antenna) using live data from the control loop.
- Persist parameter tweaks so each dance remembers its last settings between runs.
1. Backend design (SimpleDances/SimpleDances/main.py)
----------------------------------------------------
- Import `AVAILABLE_MOVES` + antenna metadata from the dance library, and pre-compute a catalog: name, friendly label (title case), description, default params, metadata (duration, etc.).
- Build helpers to:
* Load/save persisted parameters (JSON file adjacent to main.py). Structure: `{ "globals": {"bpm": float, "amplitude_scale": float}, "dances": {dance_name: {param: value}} }`.
* Merge saved params with defaults per dance.
* Derive UI specs for each param (type, slider min/max/step, unit, display multiplier) using heuristics based on the param name (e.g. `_rad` => degrees slider ±(default*3 capped), `_m` => centimeters range, `subcycles` => 0-4, `phase_offset` => 0-1, enumerations for waveform/antenna moves).
* Convert between internal units and UI units when serving values + when updates arrive.
- Shared runtime state guarded by a `threading.Lock`: selected dance name, per-dance params, BPM, amplitude scale, playing flag, timestamps, last computed offsets for visualization, file persistence timestamps, etc.
- Settings API endpoints on `self.settings_app`:
* `GET /api/dances` -> list of dances (name, label, description).
* `GET /api/state` -> current selection, playing flag, bpm, amplitude scale, parameter specs for the selected dance (values already converted for UI), and last-saved timestamp.
* `POST /api/select` -> pick a dance (payload: `{name}`), responds with updated param specs + selection.
* `POST /api/params` -> update parameters for the (selected) dance; payload includes `name` + `params` dictionary in UI units; convert, persist, respond with new specs.
* `POST /api/globals` -> update BPM and amplitude scale with validation + persistence.
* `POST /api/toggle` -> set playing flag (payload `{"playing": bool}`) and resets timing when toggling on.
* `POST /api/reset` -> reset a dance back to defaults (payload `{"name": ...}`) with save + updated specs.
* `GET /api/visualization` -> return most recent normalized offsets (position/orientation/antennas arrays) for front-end animation plus playing + bpm (read-only, polled at ~10–15 Hz by UI).
- Control loop logic:
* On `run`, load ReachyMini, ensure motors enabled as needed (maybe only when playing), instantiate start time.
* Inside loop (50–100 Hz), read `state` snapshot; if playing and a dance is selected, compute beat time using global BPM, call the corresponding move function with stored params, scale offsets by amplitude scale, convert to head pose with `create_head_pose`, and send `reachy_mini.set_target(head=head_pose, antennas=...)`. If stopped, gradually go to neutral pose (or hold last command) to avoid abrupt freeze.
* Update shared `latest_offsets` for visualization each cycle, store for `/api/visualization`.
* Sleep for ~0.02s.
- Persist JSON whenever params/globals change (debounce by writing immediately under lock).
- Handle graceful shutdown (stop flag already provided); ensure motors disabled on exit.
2. Front-end (SimpleDances/SimpleDances/static/{index.html,style.css,main.js})
-----------------------------------------------------------------------------
- Layout: split page with header, global controls, dance selector, parameter panel, start/stop button, and visualization canvas/bars.
- Use CSS with pastel gradient, glassmorphism cards, responsive grid for parameter controls.
- JS boot flow:
* Fetch `/api/dances` once for the list (populate `<select>` or tiles).
* Fetch `/api/state` and render: selection (pre-select from list), global slider values, playing state, params grid.
* On selection change -> POST `/api/select` then update UI.
* Parameter controls: for each spec (value + slider + numeric). Both inputs stay in sync and `debounce` POST `/api/params` updates; show “saved” indicator and disable controls while saving to avoid jitter.
* Reset button -> POST `/api/reset`.
* Start/stop toggle button -> POST `/api/toggle`.
* Global BPM + amplitude sliders with numeric inputs -> POST `/api/globals` when changed (debounced) with validation (BPM 40–180, amplitude 0–2.0 as slider requirements hint).
- Visualization: create `<canvas>` or `<svg>` area that animates arcs/waves based on telemetry from `/api/visualization`. Poll every ~150 ms and animate smoothly using requestAnimationFrame. Map the 8 DoF to color-coded bars/rings (e.g., 3 orientation lines, 3 translation pulses, 2 antenna bars); amplitude drives height/opacity to satisfy “each DoF has an impact”. Provide fallback animation even when not playing (dim, idle oscillation) to keep it “beautiful and simple”.
3. Persistence + utilities
--------------------------
- JSON file path: `SimpleDances/SimpleDances/dance_params.json` (auto-created). On failure to load parseable JSON, fall back to defaults but keep file for next writes.
- Provide helper to sanitize payloads and ensure only known params are stored.
- On each save, update `state["last_saved"]` so UI can display “Saved at …”.
4. Testing / validation
-----------------------
- Manual: lint via running `python -m compileall` or `uv run`? (Not necessary yet but consider). Without hardware, run `python SimpleDances/SimpleDances/main.py` in dry-run to ensure no import errors and that endpoints accept sample requests.
- UI: open `index.html` via app host after hooking to CLI environment (can't do now, but ensure markup includes helpful fallback text + `aria` labels).
Open questions / assumptions
----------------------------
- Slider heuristics rely on parameter names; confirm tomorrow whether ranges feel right. Might need fine-tuning later.
- Visualization currently planned as polling endpoint; if future requirement wants streaming/websocket, architecture allows swap.