diff --git a/CLAUDE.md b/CLAUDE.md index 1610f97..805b05f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -30,6 +30,11 @@ 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.** +`accessibility/docs/00-dev-setup.md` — how this tree is put together and why: +the two-tree arrangement, prerequisites, building a dev tree from scratch, the +everyday commands, and how publishing strips the game out. Read it if anything +about the setup surprises you. + Then `accessibility/docs/README.md` maps the rest: architecture, hooking strategy, the phased plan, open questions, decisions. diff --git a/accessibility/docs/00-dev-setup.md b/accessibility/docs/00-dev-setup.md new file mode 100644 index 0000000..720923d --- /dev/null +++ b/accessibility/docs/00-dev-setup.md @@ -0,0 +1,224 @@ +# Development setup + +How to get from nothing to a tree you can run, test and publish from. The +arrangement is a little unusual, because the mod lives inside a copy of a +commercial game that must never be published. + +**If you are already set up**, the only things you need daily are +[Everyday commands](#everyday-commands) and [Publishing](#publishing). + +--- + +## The two trees + +This repository exists in two forms, and the same `CLAUDE.md` ships in both, so +check which one you are in: + +| | **Development tree** | **Standalone mod repo** | +|---|---|---| +| Contents | The whole extracted game (1838 files) **plus** `accessibility/` | `accessibility/` and the docs only | +| Beside `accessibility/` | `main.lua`, `states/`, `models/`, … | nothing | +| Can you run the game? | Yes | **No** | +| Can you run the testbed? | Yes | **No** | +| Remote | **None, deliberately** — see [Publishing](#publishing) | `code.iamtalon.me/talon/alchemist-accessibility` | +| Where it comes from | You build it, below | Generated from the dev tree by `publish.sh` | + +The standalone repo is **derived, never developed in directly**. Every publish +rewrites its history from scratch, so any commit made there is destroyed on the +next publish. Always work in the development tree. + +Everything outside `accessibility/` in the dev tree is the vanilla game: read-only +reference material. You read it to find out how the game works; you patch it only +where the docs sanction, which currently means exactly one line. + +--- + +## What you need + +| | Why | Notes | +|---|---|---| +| **The game, 0.4.2, as an extracted source folder** | The thing being modded | A directory containing `main.lua` and `conf.lua`. **Not** a packed `.love`, **not** the Steam build — see below. | +| **LÖVE 11.5** | Runs the game | `conf.lua` pins `t.version = "11.5"`. Installed here at `C:\Program Files\LOVE\`. Use **`lovec.exe`**, not `love.exe`. | +| **Standalone Lua 5.4** | Unit tests and syntax checks without launching the game | `lua` and `luac` on PATH. | +| **A screen reader, or nothing** | To hear the output | Tolk drives NVDA / JAWS / System Access and falls back to SAPI 5. Dev here uses **NVDA**. Speech is also mirrored to the console, so you can verify from a log with no reader running at all. | +| **`uv` (for `uvx`)** | `git-filter-repo` at publish time | Only needed when publishing. | + +Optional: `luacheck`. `.luacheckrc` is configured (`std = "min+alch"` with an +explicit globals list) but the linter is not currently installed — `luac -p` is +what actually gets run. + +### Why the game must be an extracted folder + +`ffi.load("Tolk")` goes through the **OS** loader, not LÖVE's virtual filesystem, +so the TTS DLLs must exist as real files on disk. They can never live inside a +`.love` archive. This is also why the mod loads them by absolute path via +`love.filesystem.getSource()`. See `accessibility/vendor/love2talk/VENDORED.md`. + +--- + +## Building the development tree from scratch + +**1. Extract the game** into a working directory. This tree lives at +`D:\code\Sulphur Memories Alchemist 0.4.2 sanctified`. + +**2. Commit the pristine game and tag it**, *before* adding any mod code, so the +baseline is genuinely clean: + +``` +git init +git add . +git commit -m "Vanilla Sulphur Memories: Alchemist 0.4.2" +git tag vanilla-0.4.2 +``` + +The tag holds 1838 files and **no `accessibility/` directory**. That is the whole +point of it: it is what makes the footprint check below trustworthy. + +**3. Add `accessibility/`** — copy it in, or clone the standalone repo and move +its `accessibility/` folder into place. + +**4. Add the one line to `main.lua`.** In `love.load()`, immediately after +`console.prepare()`: + +```lua +require("accessibility").initialize() --ACCESSIBILITY MOD: sole entry point +``` + +`accessibility/publish/install.patch` applies exactly this. The placement is not +arbitrary: by that point templates are preprocessed, keybindings are loaded, +`states.setup()` has run and the console canvas exists — and it is still before +the first `states.switch()`. + +**5. Check the TTS DLLs survived the copy.** `accessibility/lib/` must contain +`Tolk.dll`, `nvdaControllerClient64.dll` and `SAAPI64.dll`. + +⚠ `.gitignore` has a blanket `*.dll` with a deliberate `!accessibility/lib/*.dll` +un-ignore. If you ever restructure that folder, the DLLs will silently stop being +tracked and the mod will be mute for anyone who clones it. + +**6. Verify.** Run the [everyday commands](#everyday-commands). A working setup +prints, at startup: + +``` +[accessibility] TTS: available +[accessibility] speech channel: yes +[speech]! Main menu +``` + +`speech channel: NO` means the DLLs loaded but nothing is listening — start a +screen reader, or expect SAPI. + +--- + +## Everyday commands + +Run all of these after any change. The testbed in particular: it has caught +essentially every bug in this project, and a change that looks obviously correct +is exactly the kind that fails it. + +``` +cd "D:/code/Sulphur Memories Alchemist 0.4.2 sanctified" + +lua accessibility/tests/test_history.lua # pure Lua, instant +luac -p accessibility/*.lua # syntax only, no LOVE needed + +rm -rf ~/AppData/Roaming/LOVE/Alchemist # clean save +"C:/Program Files/LOVE/lovec.exe" . --a11y-test # ~4 min + +git diff --stat vanilla-0.4.2 -- . ':!accessibility' ':!.gitignore' ':!CLAUDE.md' +``` + +The last one **must** print `main.lua | 1 +`. That is the invariant that keeps the +mod cheap to lift onto a new game version. + +**What matters in the testbed run is `0 failures`, not the check count**, which +varies between runs because several blocks are conditional. + +To just play it: + +``` +"C:/Program Files/LOVE/lovec.exe" . +``` + +### Save data + +LÖVE writes to `~/AppData/Roaming/LOVE/Alchemist` (`t.identity = "Alchemist"` in +`conf.lua`). Deleting it is how you get a clean prologue; the testbed scenario +assumes a fresh save and will not navigate correctly without one. + +Runtime files the game also drops next to the source during dev (`config.json`, +`user.json`, `keybindings.json`, savegames) are already in `.gitignore`. + +### Reading the console + +`lovec.exe` gives a console window, and every utterance is mirrored there as a +`[speech]` line — so speech is verifiable from a log rather than only by ear: + +| Prefix | Meaning | +|---|---| +| `[speech]!` | interrupted whatever was being said | +| `[speech]*` | urgent, spoken immediately (bypasses the frame queue) | +| `[speech] ` | queued normally | + +### If something mysteriously does not speak + +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. + +--- + +## Publishing + +**The development tree has no git remote, and must not be given one.** It holds +all 1838 files of a commercial title. Pushing it anywhere would distribute the +game. + +Publishing therefore means: rebuild a separate repository that contains only the +mod, and force-push *that*. + +``` +sh accessibility/publish/publish.sh +``` + +This clones the dev tree to `../alchemist-accessibility-publish`, runs +`git-filter-repo` to keep only `accessibility/` and `CLAUDE.md`, lifts +`accessibility/publish/README.md` and `install.patch` up to the root (so a visitor +to the mod repo finds them where they expect), and drops the publish machinery +itself. + +Then **the check that matters**: it lists every path in the rewritten history and +aborts if anything that is not the mod or its docs survived. A clean run says: + +``` +clean: history contains only the mod and its docs +``` + +If it says `ABORT: non-mod files present in history`, **do not push** — a game +file leaked through the filter. + +The script prints the push commands and stops rather than pushing for you: + +``` +cd ../alchemist-accessibility-publish +git remote add origin https://code.iamtalon.me/talon/alchemist-accessibility.git +git push --force -u origin master +``` + +`--force` is not a mistake and not a recovery step. `git-filter-repo` rewrites the +history from scratch every time, so the published commits are new objects on every +publish. The mod repo is derived output; force-pushing it is the normal path. + +⚠ Paste those as **separate lines**. If a shell wraps the `remote add` line, the +URL ends up on its own and gets run as a command. + +--- + +## Rebasing onto a new game version + +Commit the new pristine tree on top of the `vanilla-0.4.2` baseline, then replay +the mod commits. The only game-file conflict possible is the single `main.lua` +line. Then run the startup self-test and read it: it tells you immediately which +patches and probes the new version broke. diff --git a/accessibility/docs/README.md b/accessibility/docs/README.md index 78b2900..0395b50 100644 --- a/accessibility/docs/README.md +++ b/accessibility/docs/README.md @@ -9,6 +9,7 @@ living handoff document: current state, every bug found and why, and the traps. | Doc | Contents | |---|---| | [scratch.md](scratch.md) | **Start here.** Working state, bugs found, gotchas, keymap, how to run the testbed. | +| [00-dev-setup.md](00-dev-setup.md) | **Setting up.** The two trees, prerequisites, building the dev tree, everyday commands, publishing. | | [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. | @@ -17,7 +18,7 @@ living handoff document: current state, every bug found and why, and the traps. ## Status -**Phases 0–5 complete.** 23 state descriptors, 5 patches, 26/26 testbed checks, +**Phases 0–5 complete.** 23 state descriptors, 5 patches, 34/34 testbed checks, history unit tests passing. **Game-file footprint: one line in `main.lua`.** Verify at any time: diff --git a/accessibility/docs/scratch.md b/accessibility/docs/scratch.md index e86df64..c58f673 100644 --- a/accessibility/docs/scratch.md +++ b/accessibility/docs/scratch.md @@ -9,6 +9,9 @@ playtesting.** Remaining work is polish, mod settings and distribution. conversation into gameplay, plus journal, character, actions and inventory — verified by the testbed, **34/34 checks**. +**Not set up yet, or unsure how the two trees relate?** → +[00-dev-setup.md](00-dev-setup.md). + ### Run the testbed (do this after any change) ``` cd "D:/code/Sulphur Memories Alchemist 0.4.2 sanctified"