Files
alchemist-accessibility/accessibility/docs
Accessibility ModandClaude Opus 5 55b19dd537 hotbar: say what the key you pressed just did
Pressing a hotbar key ran hotkey.action(state), which for an equipment
binding calls an itemActions entry's onActivation directly -- Wield,
Drink, Switch on, Pack away. None of those reach console.print or a
popup; most only play a sound. So the whole hotbar was silent: no item
name, no verb, no confirmation the key had registered at all.

patches/hotbar.lua wraps the hotbar VIEW factory, not models/hotkey:
models/hotbar.lua captures newHotkey as a file-local at require time,
and models/world.lua captures newHotbar the same way, both long before
our entry point. views/hotbar.lua is required only by the three states,
which load lazily -- the same ordering argument as patches/slider.lua.

The verb is computed BEFORE the action runs. The itemAction conditions
key off item.isEquipped, which the action itself flips, so asked
afterwards they return the opposite verb and a press that wielded would
announce "Unwield".

Also narrates the empty slot, the silent no-applicable-action branch,
binding and unbinding (sound-only in game), and action-type slots. Says
nothing when the item is missing from the inventory -- the game prints
that itself and patches/console.lua speaks it.

78 testbed checks, 0 failures. The prologue gives the player no items,
so the live path is exercised by planting a torch, binding it to slot 1,
pressing 1 twice and putting the world back.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-03 02:19:51 +02:00
..
2026-08-01 22:25:09 +02:00
2026-08-01 21:34:13 +02:00

Accessibility mod — developer documentation

Making Sulphur Memories: Alchemist 0.4.2 blind-accessible. Player-facing keymap and setup: accessibility/README.md.

Picking this up mid-stream? Read scratch.md first. It is the living handoff document: current state, every bug found and why, and the traps.

Doc Contents
scratch.md Start here. Working state, bugs found, gotchas, keymap, how to run the testbed.
00-dev-setup.md Setting up. The two trees, prerequisites, building the dev tree, everyday commands, publishing.
01-architecture.md How the game is built: states, console, level model, keybindings.
02-hooking-strategy.md How the mod attaches with (near) zero edits to game files.
03-implementation-plan.md The original six-phase plan, with outcomes.
04-open-questions.md Questions raised; see 05 for answers.
05-decisions.md Decisions made, and the D4 correction.

Status

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:

git diff --stat vanilla-0.4.2 -- . ':!accessibility' ':!.gitignore' ':!CLAUDE.md'

The three findings that shaped everything

  1. The game was already keyboard-complete. All 28 states implement keypressed, with a full rebindable-keys system. The gap was that nothing announced what was focused — so the job was narration, not reimplementation.

  2. The game already writes the text. console.print is a single chokepoint for all log messages; level.getCursorMessage() describes tiles; inventoryCursorPopup.set covers four screens. Mostly we re-route existing strings to speech rather than writing a description engine.

  3. Everything is a required singleton, and debug.getupvalue works. Module functions can be patched in place, and file-local focus variables (selectedOption, …) are readable from outside. Hence the one-line footprint.

Architecture in one breath

main.lua calls require("accessibility").initialize(). That patches module singletons (console.print, popupStack.add, inventoryCursorPopup.set, modules.slider), wraps states.switch / update / keypressed / textinput, and installs a global hotkey layer. Per-screen narration lives in accessibility/states/<statename>.lua descriptors, read via debug.getupvalue. A startup self-test reports which patches and probes still resolve — the canary for a future game version moving something.