diff --git a/CLAUDE.md b/CLAUDE.md index 4f0878e..c7f4aa5 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -40,7 +40,7 @@ wheel.js ──gesture ends(word)──▶ game.submit(word) ──result object - [game.js](src/game.js) — all level state and win logic, **pure logic, no DOM** (this is what makes it unit-testable). `submit(word)` returns a discriminated result object (`target` / `bonus` / `duplicate` / `invalid`) — the shape is specified in design doc §10. `createGame` accepts an injectable `rng` (default `Math.random`) so hint-cell selection is deterministic in tests. Economy constants live in the `ECONOMY` object at the top; never scatter coin values elsewhere. - [wheel.js](src/wheel.js) — letter wheel + pointer gestures. Hit-testing (`hitIndex`), selection (`applyHit`), and shuffle permutation (`permutationAt` + `shuffleStep`, Lehmer-code unranking stepped by a golden-ratio coprime step for a deterministic full cycle back to the initial layout) are exported pure functions for testing. Selection is bound to button *index*, not letter value, because wheels can contain duplicate letters. -- [grid.js](src/grid.js), [dictionary-card.js](src/dictionary-card.js) — DOM rendering only. grid.js takes an injected `isFound` (`game.isFound`) and marks every cell whose target word is complete with `role="button"` + an `aria-label` — that one attribute is a **three-way contract**: it is the press-feedback hook in style.css (`.cell[role]:active`), the VoiceOver button semantics, and the only thing that says "this cell opens the dictionary card" (UI doc §4-E). Swapping it for a class breaks the first two silently, and both only show up on a real device. The `role` must never appear without the `aria-label`: with just the role VoiceOver reads "A, button" — identical to a wheel letter button. grid.js also exports `snapshotText` (emoji grid for the text-only share — board *shape* only, two colors, no progress; share targets tend to drop text when files are attached, so sharing sends no image) and `snapshotBlob` (canvas PNG for the manual download button — the button is currently `hidden` in index.html, code kept for later: board as spoiler-free colored blocks plus the letter wheel; colors read from CSS variables so it follows the theme). dictionary-card.js also owns `speechSynthesis` pronunciation (`speak`/`stopSpeech`), used by both its speaker button and main.js's auto-pronounce on target hit (§6.1). Its iOS unlock rule is **not** the same as the `