docs: final handoff pass

Adds accessibility/README.md, the player-facing setup and keymap reference --
the thing to read before playtesting.

Brings the developer docs in line with what was actually built:

- docs/README.md rewritten as an index with current status and a one-paragraph
  architecture summary.
- docs/scratch.md gains a HANDOFF section: state of play, the commands to run
  after any change, the five traps that each cost real debugging time, what is
  NOT verified and why, deliberate omissions, and how to rebase onto a future
  game version.
- docs/03-implementation-plan.md gains a status banner listing where the
  implementation deliberately diverged from the plan (menu narration pulled
  forward as a blocker, levelCursorPopup not patched, tryInteract insufficient
  as a tracker filter, testbed added, no settings UI built).
- docs/04-open-questions.md gains a resolution banner: Q6 and Q8 remain open.

Also records that the testbed check count varies between runs (23-26) because
some blocks are conditional, so what matters is zero failures rather than the
total.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Accessibility Mod
2026-08-01 22:25:09 +02:00
co-authored by Claude Opus 5
parent 96ec79ed75
commit 6380998376
5 changed files with 284 additions and 15 deletions
+42 -13
View File
@@ -1,23 +1,52 @@
# Accessibility mod — documentation
# Accessibility mod — developer documentation
Research and planning for making *Sulphur Memories: Alchemist* 0.4.2 blind-accessible.
Making *Sulphur Memories: Alchemist* 0.4.2 blind-accessible.
Player-facing keymap and setup: `accessibility/README.md`.
**Picking this up mid-stream? Read [scratch.md](scratch.md) first.** It is the
living handoff document: current state, every bug found and why, and the traps.
| Doc | Contents |
|---|---|
| [01-architecture.md](01-architecture.md) | How the game is built: states, console, level model, keybindings, where text already exists. |
| [02-hooking-strategy.md](02-hooking-strategy.md) | How to attach the mod with (near) zero edits to game files. |
| [03-implementation-plan.md](03-implementation-plan.md) | Six phases, each independently testable. |
| [04-open-questions.md](04-open-questions.md) | Decisions needed before/while building. |
| [05-decisions.md](05-decisions.md) | Answers given so far, and what they imply. Supersedes Q1/Q2/Q7/Q10. |
| [scratch.md](scratch.md) | **Start here.** Working state, bugs found, gotchas, keymap, how to run the testbed. |
| [01-architecture.md](01-architecture.md) | How the game is built: states, console, level model, keybindings. |
| [02-hooking-strategy.md](02-hooking-strategy.md) | How the mod attaches with (near) zero edits to game files. |
| [03-implementation-plan.md](03-implementation-plan.md) | The original six-phase plan, with outcomes. |
| [04-open-questions.md](04-open-questions.md) | Questions raised; see 05 for answers. |
| [05-decisions.md](05-decisions.md) | Decisions made, and the D4 correction. |
## The short version
## Status
Three findings shape everything:
**Phases 0–5 complete.** 23 state descriptors, 5 patches, 26/26 testbed checks,
history unit tests passing.
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.
**Game-file footprint: one line in `main.lua`.** Verify at any time:
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.
```
git diff --stat vanilla-0.4.2 -- . ':!accessibility' ':!.gitignore'
```
3. **Everything is a `require`d 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.
## The three findings that shaped everything
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.
1. **The game was already keyboard-complete.** All 28 states implement
`keypressed`, with a full rebindable-keys system. The gap was that nothing
*announced* what was focused — so the job was narration, not reimplementation.
2. **The game already writes the text.** `console.print` is a single chokepoint
for all log messages; `level.getCursorMessage()` describes tiles;
`inventoryCursorPopup.set` covers four screens. Mostly we re-route existing
strings to speech rather than writing a description engine.
3. **Everything is a `require`d singleton, and `debug.getupvalue` works.** Module
functions can be patched in place, and file-local focus variables
(`selectedOption`, …) are readable from outside. Hence the one-line footprint.
## Architecture in one breath
`main.lua` calls `require("accessibility").initialize()`. That patches module
singletons (`console.print`, `popupStack.add`, `inventoryCursorPopup.set`,
`modules.slider`), wraps `states.switch` / `update` / `keypressed` / `textinput`,
and installs a global hotkey layer. Per-screen narration lives in
`accessibility/states/<statename>.lua` descriptors, read via `debug.getupvalue`.
A startup self-test reports which patches and probes still resolve — the canary
for a future game version moving something.