Commit Graph

4 Commits

Author SHA1 Message Date
clement e37fa9ded2 gamebook: load expanded books from PSRAM 2026-06-20 09:31:05 +02:00
clement a8af29068b feat(gamebook): full-height scrolling text + real pad mapping
CI / platformio (pull_request) Failing after 4m50s
CI / platformio (push) Failing after 10m23s
Context:
Two issues on the Freenove gamebook: (1) long passages were clipped —
the reading band was small and text overflowed; (2) the 5-way pad was
decoded wrong, so navigation felt random, and on this unit the physical
Up button is electrically dead (held = no voltage change).

Approach:
Give the reading text the whole screen height in a vertically
scrollable container, split selection from scrolling, and remap the
keys to the pad's MEASURED voltages.

Changes:
- display_ui: gamebook view reworked — compact title, a full-height
  scrollable reading container (the body wraps and scrolls, never
  clipped), and a one-line choice selector pinned at the bottom; new
  display_ui_gamebook_scroll() + reset-on-new-passage; show() gains a
  reset_scroll arg; body buffer 512 -> 1100.
- gamebook.c: controls matched to the measured ladder
  (key2=LEFT, key4=DOWN, key5=RIGHT, key1=CLICK; key3 unused; Up dead):
  Left/Right scroll the text up/down, Down cycles the answer, Click
  validates; library nav cycles tiles without needing Up.

Impact:
Long passages are fully readable (they scroll), and all four working
pad buttons do the right thing; nothing depends on the dead Up button.
Hardware-calibrated against the real pad voltages.
2026-06-19 23:56:45 +02:00
clement a70963f64a feat(gamebook): library tile picker on boot
CI / platformio (pull_request) Failing after 3m56s
CI / platformio (push) Failing after 9m50s
Context:
The gamebook played a single hard-coded book. We want the master to
boot into a library of several stories, shown as tiles, and let the
player pick one with the pad.

Approach:
Turn the gamebook component into a two-mode machine (LIBRARY / STORY).
On boot it loads /sdcard/gamebook/library.json and shows the stories as
a tile grid; selecting one loads that book's <id>.json and plays it;
finishing a story returns to the library.

Changes:
- display_ui: new library view — a 2x3 grid of title tiles with the
  selected one highlighted (display_ui_library_show/hide); it wins the
  view selector while open.
- gamebook.c: LIBRARY/STORY modes; load library.json + per-book
  <id>.json from the SD; grid navigation (up/down +/-2, left/right
  +/-1, click opens); story ending click returns to the library.
- main.c: gamebook_init only installs the pad hook; gamebook_start()
  (which opens the library) is now called after the SD + media_manager
  are up, so the boot picker actually finds the SD pack.

Impact:
The Freenove boots straight into a story picker and runs any book from
the SD library, fully offline. Hardware-validated: boots into a
6-story library.
2026-06-19 15:24:17 +02:00
clement f58b090a34 feat: gamebook mode (CYOA) on the master
CI / platformio (pull_request) Failing after 4m23s
CI / platformio (push) Failing after 9m52s
Context:
We wanted a "livre dont vous etes le heros" playable on the Freenove
master with NO model in RAM: narration as say()-rendered WAV staged on
the SD card, and navigation on the physical 5-way pad. Nothing in the
firmware drove a branching, button-navigated story before this.

Approach:
A self-contained gamebook component reads a JSON book from the SD,
drives the display and audio, and owns the 5-way pad through a
registered display_ui key hook (so display_ui keeps no dependency on
gamebook — no cycle). A dedicated full-screen gamebook view renders
each page (title / wrapped body / choice list).

Changes:
- New gamebook component: loads /sdcard/gamebook/gamebook.json; per
  passage plays its WAV (media_manager, absolute /sdcard path) and
  renders the title, wrapped text, and a choice list with a ">" cursor.
- Navigation: D-pad up/down (and left/right) move the cursor, the
  center click confirms; endings (no choices) restart on click; a
  choice interrupts the current narration (media_manager_stop + play).
- display_ui: add display_ui_set_key_hook (consume keys when a takeover
  mode is active) and a dedicated gamebook view (title + height-bounded
  body band + reserved bottom menu band) with display_ui_gamebook_show
  / display_ui_gamebook_hide; the gamebook view wins the view selector
  while open.
- game_endpoint: POST /game/gamebook[?action=stop] to start/stop.
- ota_server: bump max_uri_handlers 20 -> 22 for the new endpoint.
- main: call gamebook_init() once the buttons are up.

Impact:
The Freenove plays a branching audio gamebook driven entirely by the
pad, fully offline (no gateway, no model). Hardware-validated end to
end: cursor navigation, click select, WAV narration from SD, endings
restart.
2026-06-19 14:30:37 +02:00