Files
alchemist-accessibility/accessibility/docs
Accessibility ModandClaude Opus 5 9945703fb7 Menu narration + code-driven testbed
Pulls menu focus narration forward from Phase 4: it was a blocker, since the
screen name was spoken but not the selected option, so the game could not be
started at all.

Game-file footprint unchanged: still one line in main.lua.

- menus.lua: descriptor driver supporting both D3 backends (upvalue probe and
  patched-announce), sharing one render per screen. Probe self-test included.
- Descriptors for main_menu, settings_menu, load_game, new_game, narration.
- testbed.lua: drives the game by code via love.event.push, so input takes the
  same path as a human keypress. Coroutine-based, and navigates by READING focus
  rather than counting keypresses, which drifts when options are disabled.

Three bugs found by the testbed and fixed:

1. love.keypressed was still bound to the pre-wrapper states.keypressed.
   states.setup() captures love[callback] by value and runs before us, and
   main.lua does not define love.keypressed itself, so wrapping the states table
   field alone had no effect. Now reassigns love.keypressed/textinput.

2. Focus can move with no keypress: main_menu.mousemoved assigns selectedOption
   from cursor position, silently overriding selection including at startup.
   Focus is now polled in the update hook instead of announced only on keypress.

3. Probes sometimes need chaining. narration.keypressed only calls
   continueNarration(), so the text locals are upvalues of that inner function.

Verified: main menu -> new game -> name entry -> intro narration -> gameplay,
8/8 checks passing, including console.print capture and its (x2) fold.

Known gap: ingame_dialogue announces 'Game' and reads no dialogue text.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-01 20:53:29 +02:00
..

Accessibility mod — documentation

Research and planning for making Sulphur Memories: Alchemist 0.4.2 blind-accessible.

Doc Contents
01-architecture.md How the game is built: states, console, level model, keybindings, where text already exists.
02-hooking-strategy.md How to attach the mod with (near) zero edits to game files.
03-implementation-plan.md Six phases, each independently testable.
04-open-questions.md Decisions needed before/while building.
05-decisions.md Answers given so far, and what they imply. Supersedes Q1/Q2/Q7/Q10.

The short version

Three findings shape everything:

  1. The game is already keyboard-complete. All 28 states implement keypressed; there's a full rebindable-keys system with contexts. The accessibility gap is that nothing announces what is focused — not that things are unreachable. This makes the job much smaller than a typical mouse-driven game.

  2. The game already writes the text we need to speak. console.print is a single chokepoint for all log messages. level.getCursorMessage() returns tile/creature descriptions. getCursorPopupStats() feeds the item popups in five screens. We are mostly re-routing existing strings to speech, not writing a description engine.

  3. Everything is a required singleton, and debug.getupvalue works. Module functions can be monkey-patched in place, and the file-local selectedOption variables in menu states are readable from outside. A one-line bootstrap in main.lua is the only unavoidable edit.

Proposed footprint: 1–3 lines added to main.lua, everything else new files under accessibility/. A git baseline tagged vanilla-0.4.2 makes re-application on future versions a rebase.