Skip to content

Latest commit

ย 

History

History
284 lines (209 loc) ยท 11.4 KB

File metadata and controls

284 lines (209 loc) ยท 11.4 KB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) for working with this codebase.


Project Philosophy: Spec-Driven Development with OpenSpec

This project uses OpenSpec for structured change management. All specifications are maintained in the openspec/ directory as the Single Source of Truth.

Directory Context

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

OpenSpec Workflow

For New Features

/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

For Bug Fixes

/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

AI Agent Rules

  1. Always check openspec/specs/ first - This is the source of truth
  2. Use /opsx:propose for changes - Never edit specs directly
  3. Follow delta spec format - ADDED/MODIFIED/REMOVED sections
  4. Archive completed changes - Keep changes/ clean

Code Generation Rules

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

Commands

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.js

Architecture

Mind Gym is a zero-dependency browser-based memory training game (Vanilla JS + Tailwind CSS). No bundler โ€” static files are served directly.

Three-Layer State Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           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  โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Module Loading Order (index.html script tags)

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.

Key Files

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 Design Principles

What is a Deep Module?

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

Benefits of Deep Modules

  1. Locality โ€” Changes, bugs, and knowledge concentrated in one place
  2. Leverage โ€” High capability per unit of interface
  3. Testability โ€” Each module independently testable

Game Modes

  1. Classic โ€” Flip cards to match pairs, record time and moves
  2. Countdown โ€” Time limit per difficulty level
  3. Daily Challenge โ€” Generate seed from date + difficulty + theme (global same deck)
  4. N-back โ€” Determine if current card matches N steps ago (hotkey: J)
  5. Delayed Recall โ€” Post-game test to check which cards appeared

localStorage Key Naming Convention

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

CSS Workflow

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.

Deployment

GitHub Actions (pages.yml) runs lint โ†’ test โ†’ prepare:deploy โ†’ upload dist/ to GitHub Pages (triggered on push to master).


Code Style

  • 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

Testing Strategy

Test Coverage

  • Total tests: 291 (19 test suites)
  • Key modules tested: storage, stats, fsrs, game-state, game-manager, modal-manager

Test Patterns

// 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');
  });
});

Changelog

All changes are recorded in the changelog/ directory.


currentDate

Today's date: 2026/05/08.


Project Status: Final Release (v1.11.0)

Last major refactoring: 2026-05-08

For Successor Models

  • 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

Key Architecture Decisions

  1. ADR-0001: Three-layer state architecture (Settings โ†’ GameState โ†’ ModeState)
  2. ADR-0002: i18n strategy (browser auto-detect, zh/en dictionary)
  3. ADR-0003: PWA offline-first with Service Worker cache-first strategy