# Reachy Tales — Continuation Guide Voice-driven story adventures for Reachy Mini. Pure-TS [`story-engine`](packages/story-engine/) library + JS HF Space app. ## Status - Plan: [docs/superpowers/plans/2026-04-29-reachy-tales.md](docs/superpowers/plans/2026-04-29-reachy-tales.md) — 28 tasks, all done. - Spec: [docs/superpowers/specs/2026-04-29-reachy-tales-design.md](docs/superpowers/specs/2026-04-29-reachy-tales-design.md). - 44 tests pass (41 engine + 3 bridge). `npm run build` clean (~72 KB JS). ## Layout - [packages/story-engine/](packages/story-engine/) — pure-TS library, no DOM/robot/LLM deps. Public API in [src/index.ts](packages/story-engine/src/index.ts). - [src/](src/) — Vite app. [src/story-bridge.ts](src/story-bridge.ts) wires the engine to OpenAI Realtime + the Reachy Mini JS SDK. - [content/](content/) — translated English story data (`narrator/`, `story_pirates/`). Schema: [content/SCHEMA.md](content/SCHEMA.md). - [tests/](tests/) — bridge integration test (root), uses Vitest with [vitest.config.app.ts](vitest.config.app.ts). - [Dockerfile](Dockerfile) + [nginx.conf](nginx.conf) — multistage build; nginx proxies `/openai/v1/*` to api.openai.com. ## Commands ```bash npm install npm test --workspace story-engine # 41 engine tests npm run test:app # 3 bridge tests npm run test:all # both npm run dev # http://localhost:5173 npm run build # tsc + vite build → dist/ ``` ## Reachy Mini SDK Pinned to `v1.7.0` via jsDelivr CDN in [src/main.ts](src/main.ts). Upstream: - Repo: https://github.com/pollen-robotics/reachy_mini - **AGENTS.md (read this before changing SDK integration):** https://github.com/pollen-robotics/reachy_mini/blob/main/AGENTS.md - JS lib source: https://github.com/pollen-robotics/reachy_mini/blob/main/js/reachy-mini.js - Reference conversation app (plumbing was copied from here): https://huggingface.co/spaces/tfrere/reachy-mini-minimal-js-conversation-app ## Adaptations from spec — read before changing the bridge - `OpenaiRealtimeClient` API differs from the plan's draft: event-based via `on()`, no `updateSession()`, returns tool results via `sendToolResponse(callId, output)`. The bridge restarts the session on every story transition (not just voice changes) — visible as a small audio gap. To eliminate, add a `session.update` event-send path in [src/openai-realtime.ts](src/openai-realtime.ts) and use it when the voice doesn't change. - App-side [tsconfig.app.json](tsconfig.app.json) disables `noUncheckedIndexedAccess` because the copied reference plumbing ([src/move-player.ts](src/move-player.ts), [src/head-wobbler.ts](src/head-wobbler.ts)) does matrix math with direct array indexing. The engine workspace keeps the strict setting. - `exactOptionalPropertyTypes` is on. Engine code uses conditional spreads (`...(v !== undefined && { k: v })`) instead of literal `undefined` assignments — see [packages/story-engine/src/loader.ts](packages/story-engine/src/loader.ts) and [packages/story-engine/src/engine.ts](packages/story-engine/src/engine.ts). ## Untested (require physical infra) [docs/playtest.md](docs/playtest.md) is the v1 acceptance checklist. None of those items have been verified — they need a real Reachy Mini, an OpenAI Realtime key, and a browser. CI does not cover them. ## Open content gaps [content/story_pirates/storylines/chapter1/](content/story_pirates/storylines/chapter1/) has 17 nodes. The original French source referenced 28 follow-up nodes that were never authored. Those `action.next` refs were stripped during translation review. To extend the story, author the missing follow-up nodes — many leaf nodes have `actions: []` as a result. ## HF Space deployment The Space at https://huggingface.co/spaces/Nico-robot/reachy-tales is the only remote. To deploy a change: ```bash git push hf main # the `hf` remote was added by the initial create ``` The Space auto-builds the Docker image (~1–2 min) and serves on the HF-assigned URL. Logs visible in the Space UI. If `hf` remote is missing on a fresh clone: ```bash git remote add hf https://huggingface.co/spaces/Nico-robot/reachy-tales ``` To recreate the Space from scratch (one-time): ```bash hf auth login # if not authed hf repos create reachy-tales --repo-type space --space-sdk docker git remote add hf https://huggingface.co/spaces/Nico-robot/reachy-tales git push -u hf main ```