docs: how to set up, run and publish this tree

The setup is unusual enough to need its own page, and the facts were
scattered across scratch.md, CLAUDE.md and publish.sh: the mod is developed
inside a copy of a commercial game, so the dev tree deliberately has no
remote and publishing means rebuilding a filtered repo and force-pushing
that instead.

docs/00-dev-setup.md covers the two-tree arrangement and which one you are
in, prerequisites and why the game must be an extracted folder rather than
a .love (ffi.load goes through the OS loader), building a dev tree from
scratch including the vanilla-0.4.2 baseline tag and the one main.lua line,
the everyday commands, the save location, reading the [speech] console and
the startup self-test, and the publish flow with its leak check.

Linked from CLAUDE.md and the docs index. No code change.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
Accessibility Mod
2026-08-02 02:16:21 +02:00
co-authored by Claude Opus 5
parent 973e62c8fe
commit 7ce429c2fb
4 changed files with 234 additions and 1 deletions
+5
View File
@@ -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 traps that have already cost real debugging time, and what is verified versus
merely written. **Read it first, and update it before you finish.** 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 Then `accessibility/docs/README.md` maps the rest: architecture, hooking
strategy, the phased plan, open questions, decisions. strategy, the phased plan, open questions, decisions.
+224
View File
@@ -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.
+2 -1
View File
@@ -9,6 +9,7 @@ living handoff document: current state, every bug found and why, and the traps.
| Doc | Contents | | Doc | Contents |
|---|---| |---|---|
| [scratch.md](scratch.md) | **Start here.** Working state, bugs found, gotchas, keymap, how to run the testbed. | | [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. | | [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. | | [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. | | [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 ## 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. history unit tests passing.
**Game-file footprint: one line in `main.lua`.** Verify at any time: **Game-file footprint: one line in `main.lua`.** Verify at any time:
+3
View File
@@ -9,6 +9,9 @@ playtesting.** Remaining work is polish, mod settings and distribution.
conversation into gameplay, plus journal, character, actions and inventory — conversation into gameplay, plus journal, character, actions and inventory —
verified by the testbed, **34/34 checks**. 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) ### Run the testbed (do this after any change)
``` ```
cd "D:/code/Sulphur Memories Alchemist 0.4.2 sanctified" cd "D:/code/Sulphur Memories Alchemist 0.4.2 sanctified"