This file provides guidance to Claude Code (claude.ai/code) for working with this codebase.
This project uses OpenSpec for structured change management. All specifications are maintained in the openspec/ directory as the Single Source of Truth.
| Directory | Purpose |
|---|---|
openspec/specs/ |
Capability specifications (source of truth) |
openspec/rfc/ |
Architectural decision records |
openspec/changes/ |
Active change proposals |
openspec/explorations/ |
Research artifacts |
docs/ |
User guides, tutorials, and architecture overview |
changelog/ |
Version history and release notes |
/opsx:propose "add leaderboard sharing"
โ Creates openspec/changes/add-leaderboard-sharing/
โ Generates proposal.md, specs/, design.md, tasks.md
/opsx:apply
โ Implements tasks from tasks.md
โ Marks completed items with [x]
/opsx:archive
โ Merges delta specs into openspec/specs/
โ Moves change to archive/ with date prefix
/opsx:explore
โ Investigate the issue
โ Create exploration notes in openspec/explorations/
/opsx:propose "fix timer pause bug"
โ Create structured fix proposal
/opsx:apply โ /opsx:archive
- Always check openspec/specs/ first - This is the source of truth
- Use /opsx:propose for changes - Never edit specs directly
- Follow delta spec format - ADDED/MODIFIED/REMOVED sections
- Archive completed changes - Keep changes/ clean
| Rule | Description |
|---|---|
| New Features | Use /opsx:propose to create change proposal first |
| Spec Changes | All changes to specs go through OpenSpec workflow |
| Implementation | 100% compliance with the spec in openspec/specs/ |
| No Gold-Plating | Do not add features not defined in specs |
npm test # Run Jest unit tests (291 tests)
npm run lint # Check code formatting with Prettier
npm run format # Auto-format all files
npm run build:css # Compile Tailwind CSS โ assets/app.css (minified)
npm run prepare:deploy # build:css + copy files to dist/Run a single test file:
npx jest __tests__/helpers.test.jsMind Gym is a zero-dependency browser-based memory training game (Vanilla JS + Tailwind CSS). No bundler โ static files are served directly.
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Settings (Persistent) โ
โ sound, vibrate, theme, accent, volume... โ
โ โ src/settings-manager.js โ
โ โ Auto-persist to localStorage โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ GameState (Runtime Core State) โ
โ difficulty, started, paused, elapsed... โ
โ [Delegates to GameManager for card state] โ
โ โ src/game-state.js โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ ModeState (Mode-Specific, On-Demand) โ
โ โ
โ NBackState: running, timer, seq, idx... โ
โ RecallState: lastGameValues, correctSet โ
โ โ src/nback-state.js, src/recall-state.js โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
src/keys.js โ src/utils.js โ src/shared.js โ src/stats.js โ src/achievements.js โ src/modes.js
โ src/import-export.js โ src/storage.js โ src/fsrs.js โ src/game-manager.js โ src/modal-manager.js
โ src/i18n.js โ src/effects.js โ src/pools.js โ src/timer.js โ src/confetti.js
โ src/ui-events.js โ src/ui.js โ app.js
Each src/ module exposes a global object (e.g., window.RememberStorage, window.RememberI18n). app.js is the game orchestrator consuming all modules.
| File | Responsibility |
|---|---|
app.js |
Game main loop, state machine, all mode logic (~2275 lines) |
src/game-state.js |
Runtime state coordinator, delegates to GameManager |
src/game-manager.js |
Deep module: card flip/match/win logic (flip, reset, getState) |
src/modal-manager.js |
Deep module: modal open/close/focus trap (open, close) |
src/settings-manager.js |
User preferences with auto-persist (get, set, getAll, setAll) |
src/nback-state.js |
N-back mode state: running, timer, sequence, stats |
src/recall-state.js |
Delayed recall mode: generateTest, submitAnswer |
src/shared.js |
Shared utilities: isPlainObject, clampInt, clampNumber |
src/storage.js |
localStorage CRUD โ settings, scores, stats, achievements |
src/stats.js |
Statistics normalization and aggregation logic |
src/achievements.js |
Achievement definitions and check logic |
src/modes.js |
Pure logic for N-back and recall tests |
src/import-export.js |
Backup/restore data normalization |
src/fsrs.js |
FSRS-4.5 spaced repetition algorithm |
src/i18n.js |
zh/en dictionary; auto-detect browser language |
src/ui.js |
DOM element bindings (single source of truth for elements) |
src/ui-events.js |
Event listener registration |
src/pools.js |
Card face asset pools (emoji, numbers, letters, shapes, colors) |
src/timer.js |
Countdown and timer management |
src/effects.js |
Web Audio API sound effects and Vibration API |
src/confetti.js |
Canvas 2D victory animation |
sw.js |
Service Worker: cache-first for resources, network-first for navigation |
Deep Module = Small interface + Large implementation
Example: GameManager has only 3 public methods but hides a complete state machine:
// src/game-manager.js - Deep Module Interface
window.RememberGameManager = {
flip(cardIndex, cardValue), // Returns { matched, won, state }
reset(totalPairs), // Reset game state
getState(), // Get current state snapshot
};Hidden complexity includes:
- Card flip validation
- Match detection algorithm
- Win condition checking
- State transitions
- Move counting
- Locality โ Changes, bugs, and knowledge concentrated in one place
- Leverage โ High capability per unit of interface
- Testability โ Each module independently testable
- Classic โ Flip cards to match pairs, record time and moves
- Countdown โ Time limit per difficulty level
- Daily Challenge โ Generate seed from date + difficulty + theme (global same deck)
- N-back โ Determine if current card matches N steps ago (hotkey: J)
- Delayed Recall โ Post-game test to check which cards appeared
All keys use memory_match_ prefix:
| Key Pattern | Purpose |
|---|---|
_settings |
User settings |
_best_<difficulty> |
Best score per difficulty |
_lb_<difficulty> |
Leaderboard per difficulty |
_achievements |
Achievement data |
_stats |
Statistics data |
_adaptive |
Adaptive rating (600โ1600) |
_mastery_<theme> |
FSRS mastery data per theme |
_daily_<YYYY-MM-DD>_<difficulty> |
Daily challenge completion status |
Source file: styles/app.css โ Compiled via Tailwind CLI to assets/app.css.
Run npm run build:css after editing styles/app.css. Do not edit assets/app.css directly.
GitHub Actions (pages.yml) runs lint โ test โ prepare:deploy โ upload dist/ to GitHub Pages (triggered on push to master).
- Prettier: Single quotes, trailing commas, 100 character line width, 2-space indent, LF
- Commit Format: Conventional Commits (
feat:,fix:,docs:,style:,test:,chore:,ci:,spec:) - Allowed PR Scopes:
ci,deps,docs,ui,gameplay,tooling,storage,i18n,pwa
- Total tests: 291 (19 test suites)
- Key modules tested: storage, stats, fsrs, game-state, game-manager, modal-manager
// Pattern: Test deep module interface
describe('GameManager', () => {
test('flip returns match result', () => {
const gm = new GameManager(6);
const result = gm.flip(0, 'card1');
expect(result).toHaveProperty('matched');
expect(result).toHaveProperty('won');
expect(result).toHaveProperty('state');
});
});All changes are recorded in the changelog/ directory.
Today's date: 2026/05/08.
Last major refactoring: 2026-05-08
- All specs are in
openspec/specs/ - User docs are in
docs/ - Architecture decisions in
openspec/rfc/ - Follow OpenSpec workflow for any changes
- This project is in maintenance-only mode
- ADR-0001: Three-layer state architecture (Settings โ GameState โ ModeState)
- ADR-0002: i18n strategy (browser auto-detect, zh/en dictionary)
- ADR-0003: PWA offline-first with Service Worker cache-first strategy