Summary
game.js is a single 2,931-line file containing at least six unrelated concerns plus a large amount of module-level mutable state (currentAge, totalStars, playerLevel, currentLanguage, โฆ around lines 1552โ1569). It's the file nearly every gameplay PR must touch, which guarantees merge conflicts and makes the code hard to test. Splitting it up is the single highest-leverage refactor for making this project contributable.
What lives in game.js today
AdaptiveLearningEngine + LearningAnalytics (difficulty adjustment, spaced repetition, session tracking) โ top of file
- Accessibility settings persistence (~line 518)
- Word/curriculum data and category definitions
- Multi-language support glue (
MultiLanguageSupport, translation lookups ~lines 1622โ1644, 1972, 2039)
- Speech synthesis (voice selection,
speakWord ~lines 2099โ2114)
- Core game state machine, DOM manipulation, and screen navigation
- Progress persistence via scattered
localStorage calls (lines 159, 518, 1552โ1561, 1703โ1712, 2092โ2093)
advanced-systems.js (26 KB) and ai-agent.js (26 KB) overlap with some of this and should be considered in the same pass.
Proposed structure
src/
data/words.js # curriculum/word lists (pure data)
engine/adaptive.js # AdaptiveLearningEngine
engine/analytics.js # LearningAnalytics
engine/game-state.js # score, level, stars, current word โ no DOM
i18n/language.js # MultiLanguageSupport + translations
audio/speech.js # speechSynthesis wrapper
storage/persistence.js # single module owning all localStorage keys
ui/screens.js # DOM rendering & navigation
main.js # wiring
Load via <script type="module"> in game.html (no bundler needed to start; one can be added later).
Guidance for the implementer
- Do it incrementally โ one module per PR is fine; extract pure-logic modules (
data, engine, storage) first since they need no DOM
- Centralizing the ~10 scattered
spellbloc_* localStorage keys behind one persistence module is the best first PR
- No behavior changes; the game must play identically after each extraction
- Pure modules (engine, data, storage) become unit-testable โ add tests as they're extracted
Acceptance criteria
- No single JS file over ~500 lines for game logic
- Zero direct
localStorage calls outside the persistence module
- Game plays identically (manual test: age selection โ category โ word round โ star award โ reload page โ progress retained)
Summary
game.jsis a single 2,931-line file containing at least six unrelated concerns plus a large amount of module-level mutable state (currentAge,totalStars,playerLevel,currentLanguage, โฆ around lines 1552โ1569). It's the file nearly every gameplay PR must touch, which guarantees merge conflicts and makes the code hard to test. Splitting it up is the single highest-leverage refactor for making this project contributable.What lives in game.js today
AdaptiveLearningEngine+LearningAnalytics(difficulty adjustment, spaced repetition, session tracking) โ top of fileMultiLanguageSupport, translation lookups ~lines 1622โ1644, 1972, 2039)speakWord~lines 2099โ2114)localStoragecalls (lines 159, 518, 1552โ1561, 1703โ1712, 2092โ2093)advanced-systems.js(26 KB) andai-agent.js(26 KB) overlap with some of this and should be considered in the same pass.Proposed structure
Load via
<script type="module">ingame.html(no bundler needed to start; one can be added later).Guidance for the implementer
data,engine,storage) first since they need no DOMspellbloc_*localStorage keys behind one persistence module is the best first PRAcceptance criteria
localStoragecalls outside the persistence module