38 Commits

Author SHA1 Message Date
clement 72412ca1fe content: expand kid gamebooks ~10x (815 passages)
Repo State / repo-state (pull_request) Failing after 50s
Repo State / repo-state (push) Failing after 43s
Validate Zacus refactor / validate (pull_request) Failing after 5m46s
Validate Zacus refactor / validate (push) Failing after 5m48s
Context:
The six age-11 stories were short (12-24 passages each, 87 total). We
want much deeper, more replayable branching adventures — roughly ten
times the passages.

Approach:
Rewrite each story in place (same titles/heroes/universe, same library
of six tiles), greatly expanding the world with new locations,
characters and branches. One book per file, authored in parallel, then
every graph validated independently.

Changes (passages before -> after):
- dragon_flamme   24 -> 131  (14 endings)
- ecole_sorciers  13 -> 137  (10)
- hamster_disparu 12 -> 132  (13)
- planete_zigzag  12 -> 131  (11)
- tresor_caramel  13 -> 151  (10)
- voyage_dinos    13 -> 133  (10)
- Total 87 -> 815 passages, 68 endings, ~1928 choices.

Every graph validated: YAML loads, single start, no broken gotos, every
passage reachable, <=4 choices/passage, screen<=40 & label<=38 chars,
gentle kid-safe endings (failures loop back or end softly).

Impact:
Far richer, replayable stories for the boot library. Text only here —
regenerate/stage WAVs with tools/gamebook/build_gamebook.py when the
Freenove is back online (currently unplugged).
2026-06-19 21:14:27 +02:00
clement 2b6a952e10 content: longer, more narrative kid gamebooks
Repo State / repo-state (pull_request) Failing after 40s
Repo State / repo-state (push) Failing after 40s
Validate Zacus refactor / validate (pull_request) Failing after 5m48s
Validate Zacus refactor / validate (push) Failing after 5m38s
Context:
The six age-11 stories were short and a bit dry (one or two sentences
per passage). We want richer, more immersive storytelling for a young
reader/listener.

Approach:
Rewrite all six in place (same filenames, library stays six tiles),
keeping the age-11 tone and gentle "oops, try again" endings, but with
much fuller prose: scene-setting, dialogue, a little character and
emotion, and deeper choice trees with more real branches.

Changes:
- dragon_flamme: ~600 -> ~2050 words, 24 passages, 4 endings.
- ecole_sorciers, hamster_disparu, planete_zigzag, tresor_caramel,
  voyage_dinos: each roughly doubled (~1050-1260 words), 12-13
  passages, 2-3 endings.
- All graphs validated: no broken gotos, every passage reachable.

Impact:
The boot library now tells proper little stories (the WAV narration
reads the full text; the screen shows the opening of each passage).
Text only here — rebuild/stage WAVs with the generator to deploy.
2026-06-19 16:04:56 +02:00
clement a9953172e4 content: kid-friendly gamebook library (age 11)
Context:
The gamebook tiles were filled with fairly dark adventures (haunted
manor, deaths, being eaten/frozen) — not suitable for an 11-year-old.
We want the boot library to be age-appropriate.

Approach:
Write six light, branching stories pitched at ~11 years (adventure +
humour, gentle "oops, try again" failures, never grim), and move the
six mature adventures into a non-library subfolder so they're kept but
out of the kids' picker (the generator globs game/gamebooks/*.yaml,
non-recursive). Text only — no WAV synthesis here.

Changes:
- New kid stories in game/gamebooks/: dragon_flamme, tresor_caramel,
  planete_zigzag, hamster_disparu, ecole_sorciers, voyage_dinos
  (11-17 passages each, 2-5 endings, all reachable, no broken gotos).
- Move the 6 mature adventures to game/gamebooks/aventures/ (archived,
  excluded from the library glob).

Impact:
The 6-tile boot library now offers age-appropriate stories. Build/stage
them with tools/gamebook/build_gamebook.py when ready (not done here).
2026-06-19 15:23:08 +02:00
clement bfa09b68be content: three long text gamebooks
Repo State / repo-state (push) Failing after 49s
Repo State / repo-state (pull_request) Failing after 46s
Validate Zacus refactor / validate (push) Failing after 5m38s
Context:
The gamebook engine had a single short demo. We want several long,
text-only "livre dont vous etes le heros" adventures to play on the
Freenove (and to exercise deeper branching).

Approach:
Author each as a standalone gamebook YAML in game/gamebooks/, using the
navigable format (passages with screen/text, choices as label+goto;
a choiceless passage is an ending that restarts on click).

Changes:
- game/gamebooks/tour_horloger.yaml: "La Tour de l'Horloger"
  (fantastique/temps) — 23 passages, 8 fins.
- game/gamebooks/train_de_nuit.yaml: "Le Dernier Train de Nuit"
  (mystere/huis clos) — 19 passages, 7 fins.
- game/gamebooks/ile_echos.yaml: "L'Ile aux Mille Echos"
  (aventure/survie) — 16 passages, 7 fins.

Impact:
Three richly branched stories ready to stage on the master SD with
tools/gamebook/build_gamebook.py. Graphs validated: no broken gotos,
every passage reachable, multiple endings each.
2026-06-19 14:41:54 +02:00
clement 05c4c11c0b feat: gamebook authoring + demo + bump fw
Repo State / repo-state (pull_request) Failing after 35s
Repo State / repo-state (push) Failing after 40s
Validate Zacus refactor / validate (pull_request) Failing after 5m58s
Validate Zacus refactor / validate (push) Failing after 7m16s
Context:
The new firmware gamebook mode needs a book on the Freenove SD, plus a
reusable way to author one. We also want a playable demo to prove the
whole chain (button -> navigation -> WAV narration from SD -> screen).

Approach:
Author the book in a human-friendly YAML; a generator renders each
passage's narration with macOS say (16 kHz mono, canonical WAV — the
Apple FLLR chunk is stripped so the firmware parser decodes it),
emits a compact gamebook.json, and stages WAVs + JSON onto the master
SD via POST /game/file?path=sd/gamebook/.

Changes:
- game/gamebooks/zacus_demo.yaml: a branching mini-adventure (the
  Professeur Zacus lab) — 8 passages, 3 endings.
- tools/gamebook/build_gamebook.py: reusable/idempotent generator
  (--book/--ip/--sd-dir/--dry-run); ASCII-folds on-screen text (fonts
  have no accents) while the WAV keeps the accented narration; choices
  carry label + goto (navigation is generic, D-pad + click).
- .gitignore: ignore the generated WAV pack (tools/gamebook/build/).
- Bump ESP32_ZACUS to the gamebook-mode firmware.

Impact:
Authors can write a gamebook in YAML and stage it to the Freenove in
one command; the bundled demo plays end to end, fully offline.
2026-06-19 14:31:50 +02:00
clement b80744d231 feat(game): warning scene auto-calls Zacus
Repo State / repo-state (pull_request) Failing after 46s
Validate Zacus refactor / validate (pull_request) Failing after 6m6s
Validate Zacus refactor / validate (push) Failing after 6m4s
Repo State / repo-state (push) Failing after 12m16s
Enable call_on_scene SCENE_WARNING -> 0142738200: Professeur Zacus
rings the PLIP when the scenario reaches the warning scene.
2026-06-18 15:02:51 +02:00
clement 37eab47f63 feat(voice): scenario-driven incoming calls
Repo State / repo-state (pull_request) Failing after 1m5s
Repo State / repo-state (push) Failing after 55s
Validate Zacus refactor / validate (pull_request) Failing after 6m20s
Validate Zacus refactor / validate (push) Failing after 13m3s
The phone now rings on cue from the game with NO firmware change. A
call_on_scene map (phone_directory.yaml: {SCENE_X: number}) tells the
gateway which scenes are scripted incoming calls; since the runtime
already pushes the scene to /game/step, the gateway auto-rings the PLIP
with that NPC on scene entry (deduped, once per entry). Factored a
_ring_board helper (shared by /game/call + auto-ring). Map ships empty
(no surprise rings) with commented examples for the designer.
2026-06-18 14:57:08 +02:00
clemsail 3066e63b24 feat(gateway): phone directory loader (numéro → persona/voix) 2026-06-14 22:21:27 +02:00
clemsail 56c44eaf4f feat(atelier): board field on morse/nfc/coffre/led/radio puzzles + tests + complete blocks scenario
Repo State / repo-state (pull_request) Failing after 37s
Repo State / repo-state (push) Failing after 27s
Validate Zacus refactor / validate (pull_request) Failing after 5m49s
2026-06-14 17:08:22 +02:00
clement b76f2d3c98 fix(scenario): zacus_v3 valide — act/objective/firmware_step sur les 3 puzzles
Repo State / repo-state (push) Failing after 12m35s
Validate Zacus refactor / validate (push) Successful in 17m26s
Les puzzles de zacus_v3.yaml n'avaient ni `act`, ni `objective`, ni
`firmware_step` (requis par le validateur schema V2). Ajout calqué sur
zacus_v2 : Diapason→acte 1, Piano LEFOU→acte 2, QR Archives→acte 2 ;
valeurs déduites du contenu existant (scène, runtime_steps, solution).
Le scénario valide, compile et simule désormais le playthrough complet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-13 13:07:45 +02:00
Claude Worker claude2 a481f130d6 fix(scenario): straight quotes in zacus_v3
Les guillemets typographiques servaient de pseudo-délimiteurs YAML :
les valeurs chargées contenaient littéralement “…” (endpoints LLM/TTS,
names des puzzles) et la séquence du piano valait [“L”,“E”,…] au lieu
de [L,E,F,O,U]. Conversion “”→", ‘’→', …→... ; tirets et « » français
conservés. Parse vérifié avant/après (yaml.safe_load).
2026-06-11 03:37:08 +02:00
L'électron rare 966ff731bd feat(voice-bridge): STT post-correction aliases
Server-side fuzzy alias table applied to the final STT transcript
before forwarding to /voice/intent. Closes the metier-vocabulary
gap of generic STT models (U-SON, LA 440 Hz, Zacus, ...) without
needing per-request prompt biasing — which moshi-server's Rust
runtime does not expose anyway.

Loader is soft on pyyaml (degrades to no-op if missing) and on
the yaml file itself (logs + skips on parse error). Patterns are
case-insensitive with auto word-boundaries, with a (?...) escape
hatch for advanced regex.

Per-puzzle entries layer on top of globals — firmware passes
puzzle_id in the hello frame; legacy clients omit it and get
just the global polish. Loaded once at module import; restart
voice-bridge to reload.

Unit tested on 5 representative transcripts (eu son nez -> U-SON,
diapazon -> diapason, le rasus -> Zacus, le la 440 hertz -> LA 440 Hz).
2026-05-24 01:27:47 +02:00
L'électron rare 61ca35670f feat(hints): adaptive level (group + stuck-timer)
Adds slice D_P4 of the hints engine: an adaptive level *floor* derived
from the group profile (TECH / NON_TECH / MIXED / BOTH), the elapsed
stuck-time, and the per-puzzle failed-attempt counter. The floor is
combined at the call site as
  level_served = max(level_requested, count + 1, level_floor_adaptive)
and clamped to NPC_MAX_HINT_LEVEL.

Configuration lives in game/scenarios/hints_adaptive.yaml (override
via HINTS_ADAPTIVE_PATH). When the file is absent, adaptive mode is
silently disabled (warning logged) so the engine keeps running with
the existing P3 logic.

Adds two firmware-driven endpoints:
- POST /hints/puzzle_start    seeds puzzle_started_at_ms (idempotent,
                              with optional force=true to restart)
- POST /hints/attempt_failed  bumps failed_attempts_for_puzzle, 404s
                              on unknown puzzle_id

/hints/ask gains an optional group_profile field and now reports
level_floor_adaptive, stuck_minutes, failed_attempts and
group_profile_used in every response (refusal envelope included).
Auto-trigger on stuck-timer remains firmware-side (slice D_P6) — this
slice does not poll, only serves higher levels when asked.

Tests: 35 / 35 green (26 P1+P2+P3 unchanged + 9 new). Backward
compatible by construction: when group_profile is omitted MIXED is
used and at t=0 the floor is 0, so the existing P3 decision stands.
2026-05-03 21:25:00 +02:00
L'électron rare 1ed230ebd0 feat(hints): add LLM rewrite via LiteLLM hints-deep 2026-05-03 19:02:37 +02:00
L'électron rare 7a6e2d0e89 feat(playtest): scaffold harness + 1st playtest
Phase P1 of the playtest harness design spec:
* tools/playtest/run_playtest.py — replays a playtest YAML
  against the Runtime 3 IR and compares to (or updates) a
  snapshot JSON
* game/scenarios/playtests/zacus_v3_60min_tech.playtest.yaml
  — first canonical playtest, resolves PUZZLE_LA_440 via the
  UNLOCK_LA_440 unlock event
* game/scenarios/playtests/snapshots/
  zacus_v3_60min_tech.snapshot.json — committed reference
* Makefile: new "playtest" target wiring the runner via uv

Critical-asserts evaluator and TS runner are out of P1 scope.
2026-05-03 17:17:52 +02:00
L'électron rare d31d8af180 docs: nested CLAUDE.md via init-deep
Slim root CLAUDE.md (90 lines) and add 7 nested CLAUDE.md
files for progressive disclosure. Each nested file loads
automatically when Claude reads files in that directory.

Nested files:
- game/        scenarios + NPC phrases (source-of-truth)
- tools/       Python tooling (Runtime 3, TTS, MCP, dev CLI)
- tests/       Python unittest patterns
- specs/       contracts governance
- frontend-scratch-v2/  React 19 + Blockly + Vite (legacy)
- frontend-v3/ pnpm monorepo (production target)
- desktop/     Electron Zacus Studio (macOS)

Root CLAUDE.md gains a Where-to-Look table and pointer to
nested guidance. ESP32_ZACUS submodule is intentionally not
covered (separate repo with its own CI).
2026-05-01 11:44:17 +02:00
L'électron rare 9f4501b9b9 feat: Zacus V3 complete
Phase 1: zacus_v3_complete.yaml, constants, phrases
Phase 3: ESP-NOW framework, 4 puzzle firmwares, master
Phase 4: NPC V3 profiling + game coordinator
Phase 5: XTTS-v2 Docker + voice clone generator
Phase 6: AudioCraft + BLE audio control
Phase 9: One-pager, video script, pricing, guide
2026-04-03 00:42:34 +02:00
L'électron rare d838a34e73 feat: scenario v3 with NPC/phone/fallback
Add zacus_v3.yaml extending v2 with new top-level sections:
- npc_config: LLM/STT/TTS endpoints, scene timeboxes
- telephone: Audio Kit ESP32 integration config
- fallback: SD card offline mode with manifest
- puzzles: enriched with typed solutions, 3-level hints, NPC hooks

Runtime 3 compiler validates successfully (ignores new keys).
2026-04-02 09:34:23 +02:00
L'électron rare db54b8fb12 feat: NPC conversation + puzzle + endings
Add three new phrase categories to npc_phrases:
- conversation: greeting, off_topic, encouragement
- puzzle_specific: la_detector, lefou_piano, qr
- endings: fast, normal, slow, no/many hints
2026-04-02 09:30:35 +02:00
L'électron rare dcf94b3ed6 feat: Zacus system prompt + game state endpoint
Add static personality prompt file for Professor Zacus with moods,
communication rules and in-game limits. Voice bridge now accepts
POST /game_state from ESP32 to inject dynamic scene context into the
LLM system prompt (scene, elapsed time, hints, mood, objective).
2026-04-02 09:27:34 +02:00
L'électron rare f4634f1dbe feat: NPC phrases, TTS generator, tests
- npc_phrases.yaml: full phrase bank (hints, personality,
  adaptation, bridges, false leads, ambiance) in French
- generate_npc_pool.py: batch TTS generator (Piper API)
- test_npc_engine.py: 21 unit tests for trigger logic
- test_npc_phrases_schema.py: YAML schema validation (12 tests)
- Fix FAST_PROGRESS guard: use absolute time limit to prevent
  false positives after several minutes on a scene

Impact: Sprint 3 NPC data layer complete. 33 tests passing.
2026-04-02 09:15:01 +02:00
L'électron rare 20aed903ba feat: AI integration — voice pipeline, hints engine, MCP server, analytics, security
- Voice pipeline: ESP32 WebSocket client → voice bridge → LLM → Piper TTS (Tower :8001)
- Hints engine: 3 puzzles (LA_440, LEFOU_PIANO, QR_FINALE), anti-cheat, 3 hint levels
- MCP hardware server: 6 tools (puzzle, audio, LED, camera, scenario, status), stdio transport
- Analytics: ESP32 module + 6 web endpoints + Dashboard UI with chat interface
- Security: auth middleware (Bearer NVS), rate limiting, input validation on 30 endpoints
- Frontend: code-split (1.1MB → 210KB initial), ErrorBoundary, API timeout, WS reconnect
- Tests: 24 Python + 38 TypeScript + 18 MCP = 80 project tests (+ 19 mascarade)
- Specs: AI_INTEGRATION_SPEC, MCP_HARDWARE_SERVER_SPEC, QA_TEST_MATRIX_SPEC
- Docs: SECURITY, DEPLOYMENT_RUNBOOK, voice pipeline guide, AI architecture map
- 6 AI agent definitions (.github/agents/ai_*.md)
- TUI orchestration script (tools/dev/zacus_tui.py)
- Docker compose TTS for Tower + KXKM-AI
- CHANGELOG, README, mkdocs.yml updated
- Cycle detection (DFS) in runtime3 validator
- Sprint plan: plans/SPRINT_AI_INTEGRATION.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-22 13:52:45 +01:00
Clément SAILLANT c2fc583bae Refactor scenario validation to support V2 schema and update related tests
- Updated `validate_scenario.py` to handle V2 scenario YAML files, introducing new required keys and validation logic.
- Added support for legacy V1 scenarios with an option to allow migration.
- Modified `run_content_checks.sh` to validate V2 scenarios and associated audio and printables manifests.
2026-03-05 19:29:48 +01:00
Clément SAILLANT e2bdd8b66c Add SceneGyrophare effect implementation
- Introduced SceneGyrophareConfig structure for configuration parameters.
- Implemented SceneGyrophare class with methods for creating, destroying, and updating the gyrophare effect.
- Added rendering functions for background, beams, and warning triangle.
- Integrated timer for animation updates based on frame rate.
- Created a log file for ESP32 audio kit boot information.
2026-03-01 11:41:15 +01:00
Clément SAILLANT 0aee3ca834 Hotline ringback + Freenove U_SON playlist and LEFOU sequence 2026-02-28 06:31:59 +01:00
Clément SAILLANT 520f98d2b9 freenove: publish current story/ui source of truth 2026-02-27 14:48:29 +01:00
Clément SAILLANT 0e7774a062 feat: Nettoyage des écrans inutilisés et mise à jour des références dans les scénarios 2026-02-26 11:58:27 +01:00
Clément SAILLANT feed1695c6 feat: Clean up unused screens and improve storage management
- Removed 9 unused screen JSON files: SCENE_BROKEN, SCENE_CAMERA_SCAN, SCENE_FIREWORKS, SCENE_LA_DETECT, SCENE_MEDIA_ARCHIVE, SCENE_SIGNAL_SPIKE, SCENE_WIN, SCENE_WINNER, SCENE_WIN_ETAPE.
- Updated AGENT_TODO.md to reflect the cleanup actions and results.
- Enhanced StorageManager to handle SD card access failures with a failure streak mechanism, switching to LittleFS after repeated failures.
- Added support for aliasing long action IDs to short filenames in the generator.
- Improved scenario manager to handle different key names for action IDs in YAML files.
2026-02-25 20:37:51 +01:00
Clément SAILLANT 3ac0b7d997 Refactor scene JSON configurations and enhance user logging capabilities
- Updated multiple scene JSON files to improve visual themes, effects, and transitions.
- Changed effect speeds and added missing timeline objects for better scene management.
- Enhanced SCENE_LA_DETECTOR, SCENE_LEFOU_DETECTOR, SCENE_MEDIA_MANAGER, SCENE_QR_DETECTOR, SCENE_WARNING, SCENE_WIN_ETAPE1, and SCENE_WIN_ETAPE2 with refined titles, subtitles, and symbols.
- Introduced a new user live logger script to capture serial logs during real user playtests for better debugging and analysis.
- Added a workbench export/import tool to streamline scene editing and synchronization with JSON files.
- Improved FX verificator documentation to clarify usage modes and verification processes.
2026-02-25 19:41:20 +01:00
Clément SAILLANT 229c381c3e docs: importer zacus_conversation_bundle_v3 et clôturer le blocage ZIP intake (#106)
* docs: import zacus conversation bundle v3 and close ZIP intake TODO

* tools: add reproducible validator installer and document next gates

* docs: remove ZIP terminology and align intake docs to conversation bundle

* tools: add runtime bundle validator and update docs workflow

* feat: promote gameplay scenario and enforce G3 bundle checks in CI

* docs: add deep repo analysis and next-step TODOs

* Initial plan (#107)

Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <198982749+Copilot@users.noreply.github.com>
2026-02-25 18:17:46 +01:00
Clément SAILLANT cdbbed3fd0 Add QR Unlock App implementation and schema
- Implemented QrUnlockApp class with methods for lifecycle management (begin, start, update, stop, handleEvent) and snapshot retrieval.
- Created header file for QrUnlockApp with necessary method declarations and private members.
- Added Yamale schema for scenario template to define prompt input and optional firmware snapshot.
2026-02-25 17:21:24 +01:00
Clément SAILLANT d4ccd49b3f freenove: scope QR media flow to espnow and fix boot action asset 2026-02-25 17:21:23 +01:00
Clément SAILLANT 8cccd8c3a9 freenove: add QR final flow and media-manager boot mode 2026-02-25 17:21:23 +01:00
Clément SAILLANT 8b4ef626fc chore(agents): add/update subproject + firmware agent contracts 2026-02-15 04:25:40 +01:00
Clément SAILLANT c7e4cd6b07 chore(agents): add root + subproject AGENTS contracts 2026-02-15 03:55:34 +01:00
Clément SAILLANT 67ac93a86a Merge origin/main into chore/harmonize-zacus 2026-02-14 00:21:06 +01:00
Clément SAILLANT 2915984946 feat: zacus v1 (scenario, kit MJ, printables/audio pipeline, docs, licenses) 2026-02-14 00:07:29 +01:00
Clément SAILLANT ad061e9047 Fix extraction issue by untracking generated binary assets 2026-02-13 23:15:24 +01:00