2026-08-02 01:04:25 +02:00
|
|
|
# CLAUDE.md
|
|
|
|
|
|
|
|
|
|
## What this repository is
|
|
|
|
|
|
2026-08-02 01:21:16 +02:00
|
|
|
A blind-accessibility mod for the commercial game *Sulphur Memories: Alchemist*
|
|
|
|
|
0.4.2 (LÖVE 11.5, Lua/LuaJIT). **The work here is accessibility, not game
|
|
|
|
|
development.**
|
2026-08-02 01:04:25 +02:00
|
|
|
|
2026-08-02 01:21:16 +02:00
|
|
|
This file ships in two places, so check which one you are in:
|
|
|
|
|
|
|
|
|
|
- **The development tree** — an extracted copy of the game with `main.lua` and
|
|
|
|
|
`states/` beside `accessibility/`. Everything outside `accessibility/` is the
|
|
|
|
|
vanilla game: treat it as read-only reference material. You read it to find
|
|
|
|
|
out how the game works, and you patch it only where the docs sanction.
|
|
|
|
|
- **The standalone mod repository** (`alchemist-accessibility`) — only
|
|
|
|
|
`accessibility/` and the docs; no game. You cannot run or test anything here.
|
|
|
|
|
See `README.md` for how the two relate. The sections below about running the
|
|
|
|
|
game and checking the game-file footprint apply to the development tree only.
|
|
|
|
|
|
|
|
|
|
All mod code lives in `accessibility/` either way.
|
2026-08-02 01:04:25 +02:00
|
|
|
|
|
|
|
|
If a request sounds like a game change ("make the journal readable", "the
|
|
|
|
|
inventory doesn't work"), it almost always means **"a screen reader user cannot
|
|
|
|
|
use this"** — the fix belongs in `accessibility/`, not in `states/` or `models/`.
|
|
|
|
|
|
|
|
|
|
## Read this before doing anything
|
|
|
|
|
|
|
|
|
|
`accessibility/docs/scratch.md` — a living handoff document. It carries the
|
|
|
|
|
current state of play, confirmed decisions that should not be relitigated, the
|
|
|
|
|
traps that have already cost real debugging time, and what is verified versus
|
|
|
|
|
merely written. **Read it first, and update it before you finish.**
|
|
|
|
|
|
|
|
|
|
Then `accessibility/docs/README.md` maps the rest: architecture, hooking
|
|
|
|
|
strategy, the phased plan, open questions, decisions.
|
|
|
|
|
|
|
|
|
|
`accessibility/README.md` is the *user-facing* manual — the key bindings the mod
|
|
|
|
|
adds. Update it when you add or change a key.
|
|
|
|
|
|
|
|
|
|
## Working agreements
|
|
|
|
|
|
|
|
|
|
- **The user is blind.** Every verification must be describable in text. Never
|
|
|
|
|
rely on a screenshot, and never ask them to check something visually. Console
|
|
|
|
|
output and testbed transcripts are the evidence.
|
|
|
|
|
- **Change as little game code as possible**, so the mod re-applies cleanly to
|
|
|
|
|
new game versions. Currently the entire game-side footprint is one line in
|
|
|
|
|
`main.lua`. Check it has not grown:
|
|
|
|
|
```
|
|
|
|
|
git diff --stat vanilla-0.4.2 -- . ':!accessibility' ':!.gitignore' ':!CLAUDE.md'
|
|
|
|
|
```
|
|
|
|
|
It must stay `main.lua | 1 +`. The pristine tree is tagged `vanilla-0.4.2`.
|
|
|
|
|
- **Speech must never throw.** A missing DLL degrades to silence; the game keeps
|
|
|
|
|
running. Wrappers call through to the original and return its results verbatim.
|
|
|
|
|
- **Never reveal anything outside `FoV` / `rememberedFoV`.** The mod must not
|
|
|
|
|
become a cheat.
|
|
|
|
|
|
|
|
|
|
`accessibility/docs/scratch.md` has the full invariant list; these are the ones
|
|
|
|
|
worth knowing before you write a line.
|
|
|
|
|
|
|
|
|
|
## Verify after any change
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
lua accessibility/tests/test_history.lua # pure Lua, instant
|
|
|
|
|
rm -rf ~/AppData/Roaming/LOVE/Alchemist # clean save
|
|
|
|
|
"C:/Program Files/LOVE/lovec.exe" . --a11y-test # ~4 min
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
The testbed drives the real game by code and navigates by *reading focus* rather
|
|
|
|
|
than counting keypresses. It has caught essentially every bug in this project, so
|
|
|
|
|
run it — a change that looks obviously correct is exactly the kind that fails.
|
|
|
|
|
|
|
|
|
|
**What matters is `0 failures`, not the check count**, which varies between runs
|
|
|
|
|
because several blocks are conditional.
|
|
|
|
|
|
|
|
|
|
Use `lovec.exe` (not `love.exe`) for a console. Every utterance is mirrored there
|
|
|
|
|
as a `[speech]` line, so speech is verifiable from a log rather than only by ear:
|
|
|
|
|
`!` interrupted, `*` immediate, ` ` queued.
|
|
|
|
|
|
|
|
|
|
## If something mysteriously does not speak
|
|
|
|
|
|
|
|
|
|
Run the game and read the startup self-test. It reports every patch and every
|
|
|
|
|
descriptor probe. Most menu narration reads the game's file-local variables via
|
|
|
|
|
`debug.getupvalue`, so a renamed local in a future game version shows up there as
|
|
|
|
|
`PROBE BROKEN: no upvalue 'x'` rather than as silence three screens in.
|
|
|
|
|
`ok (unset until opened)` is normal.
|