docs: add CLAUDE.md so agents start from the accessibility context

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>
This commit is contained in:
Accessibility Mod
2026-08-02 01:04:25 +02:00
co-authored by Claude Opus 5
parent e1d9995c9f
commit 18e6473dd3
3 changed files with 78 additions and 3 deletions
+75
View File
@@ -0,0 +1,75 @@
# 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.