New sessions land in what looks like a game repository and start treating the
task as game development, so the accessibility framing had to be re-explained
every time. CLAUDE.md states it up front: everything outside accessibility/ is
the vanilla game and is read-only reference, and a request phrased as a game
bug ("the journal doesn't work") means a screen reader user cannot use it.
Deliberately a pointer rather than a copy, so it cannot drift out of sync with
accessibility/docs/. It sends readers to docs/scratch.md first and carries only
what a fresh agent would otherwise get wrong: that the user is blind so no
verification may depend on seeing anything, the small-footprint rule, that
speech must never throw, the FoV rule, how to run the testbed, and how to read
the startup self-test when something is silent.
CLAUDE.md sits in the game tree, so it would show up in the footprint check
that must stay "main.lua | 1 +". Excluded there and in the three places the
docs quote that command.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
76 lines
3.4 KiB
Markdown
76 lines
3.4 KiB
Markdown
# CLAUDE.md
|
|
|
|
## What this repository is
|
|
|
|
This is an extracted copy of the commercial game *Sulphur Memories: Alchemist*
|
|
0.4.2 (LÖVE 11.5, Lua/LuaJIT) — **and the work here is a blind-accessibility mod
|
|
for it, not game development.**
|
|
|
|
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 in the rare case the docs sanction. All mod code lives in `accessibility/`.
|
|
|
|
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.
|