Major features: - Add new Word Storm falling words vocabulary game - Refactor CSS to modular architecture (global base + game injection) - Fix template literal syntax errors causing loading failures - Add comprehensive developer guidelines to prevent common mistakes Technical changes: - Word Storm: Complete game with falling words, scoring, levels, lives - CSS Architecture: Move game-specific styles from global CSS to injectCSS() - GameLoader: Add Word Storm mapping and improve error handling - Navigation: Add Word Storm configuration - Documentation: Add debugging guides and common pitfall prevention 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
26 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
🎯 IMPORTANT: Check TODO.md First!
ALWAYS check TODO.md for the current project tasks and priorities before making any changes.
The TODO.md file contains:
- 🔥 Current tasks in progress
- 📋 Pending features to implement
- 🚨 Known issues and blockers
- ✅ Completed work for reference
Make sure to update TODO.md when:
- Starting a new task
- Completing a task
- Discovering new issues
- Planning future improvements
Project Overview
Interactive English learning platform for children (8-9 years old) built as a modular Single Page Application. The system provides 9 different educational games that work with various content modules through a flexible architecture.
Key Architecture Patterns
Core System Flow
- AppNavigation (
js/core/navigation.js) - Central SPA navigation controller - ContentScanner (
js/core/content-scanner.js) - Auto-discovers available content modules - GameLoader (
js/core/game-loader.js) - Dynamically loads game and content modules - Content Engine (
js/core/content-engine.js) - Processes and adapts content for games
Module Loading System
- Games and content are loaded dynamically via
GameLoader.loadGame(gameType, contentType) - All modules register themselves on global objects:
window.GameModulesandwindow.ContentModules - Content is discovered automatically by
ContentScannerscanningjs/content/directory - JSON Content Support: New JSON-first architecture with backward compatibility to JS modules
- JSON Content Loader:
js/core/json-content-loader.jstransforms JSON content to legacy game format - Offline-First Loading: Content loads from local files first, with DigitalOcean Spaces fallback
- Games follow consistent constructor pattern:
new GameClass({ container, content, onScoreUpdate, onGameEnd })
URL-Based Navigation
- Single HTML file (
index.html) handles all navigation via URL parameters - Routes:
?page=home|games|levels|play&game=<gameType>&content=<contentType> - Browser back/forward supported through
popstateevents - Navigation history maintained in
AppNavigation.navigationHistory - Breadcrumb navigation with clickable path elements
- Top Bar: Fixed header with app title and permanent network status indicator
- Network Status: Real-time connectivity indicator (🟢 Online / 🟠 Connecting / 🔴 Offline)
- Keyboard shortcuts (ESC = go back)
Content Module Format
Rich Content Schema (New Architecture)
Content modules support rich, multimedia educational content with optional properties. The system adapts games and exercises based on available content features:
window.ContentModules.ModuleName = {
name: "Display Name",
description: "Description text",
difficulty: "easy|medium|hard|beginner|intermediate|advanced",
language: "chinese|english|french|spanish", // Target learning language
hskLevel: "HSK1|HSK2|HSK3|HSK4|HSK5|HSK6", // Chinese proficiency level
// Rich vocabulary with optional multimedia
vocabulary: {
"word_or_character": {
translation: "English translation",
prononciation: "pronunciation guide", // Optional: pronunciation guide
type: "noun|verb|adjective|greeting|number", // Word classification
pronunciation: "audio/word.mp3", // Optional: audio file
difficulty: "HSK1|HSK2|...", // Optional: individual word difficulty
strokeOrder: ["stroke1", "stroke2"], // Optional: character writing order
examples: ["example sentence 1"], // Optional: usage examples
grammarNotes: "special usage rules" // Optional: grammar context
}
// OR simple format for basic content:
// "word": "simple translation"
},
// Grammar rules and explanations
grammar: {
topic_name: {
title: "Grammar Rule Title",
explanation: "Detailed explanation",
examples: [
{ chinese: "中文例子", english: "English example", prononciation: "zhōng wén lì zi" }
],
exercises: [/* grammar-specific exercises */]
}
},
// Audio content with/without text
audio: {
withText: [
{
title: "Audio Lesson Title",
audioFile: "audio/lesson1.mp3",
transcript: "Full text transcript",
translation: "English translation",
timestamps: [{ time: 5.2, text: "specific segment" }] // Optional
}
],
withoutText: [
{
title: "Listening Challenge",
audioFile: "audio/challenge1.mp3",
questions: [
{ question: "What did they say?", type: "ai_interpreted" }
]
}
]
},
// Poetry and cultural content
poems: [
{
title: "Poem Title",
content: "Full poem text",
translation: "English translation",
audioFile: "audio/poem1.mp3", // Optional
culturalContext: "Historical background"
}
],
// Fill-in-the-blank exercises
fillInBlanks: [
{
sentence: "I _____ to school every day",
options: ["go", "goes", "going", "went"], // Multiple choice options
correctAnswer: "go",
explanation: "Present tense with 'I'"
},
{
sentence: "The weather is _____ today",
type: "open_ended", // AI-interpreted answers
acceptedAnswers: ["nice", "good", "beautiful", "sunny"],
aiPrompt: "Evaluate if answer describes weather positively"
}
],
// Sentence correction exercises
corrections: [
{
incorrect: "I are happy today",
correct: "I am happy today",
explanation: "Use 'am' with pronoun 'I'",
type: "grammar_correction"
}
],
// Reading comprehension with AI evaluation
comprehension: [
{
text: "Long reading passage...",
questions: [
{
question: "What is the main idea?",
type: "ai_interpreted",
evaluationPrompt: "Check if answer captures main theme"
},
{
question: "Multiple choice question?",
type: "multiple_choice",
options: ["A", "B", "C", "D"],
correctAnswer: "B"
}
]
}
],
// Matching exercises (connect lines between columns)
matching: [
{
title: "Match Words to Meanings",
leftColumn: ["apple", "book", "car"],
rightColumn: ["苹果", "书", "车"],
correctPairs: [
{ left: "apple", right: "苹果" },
{ left: "book", right: "书" },
{ left: "car", right: "车" }
]
}
],
// Standard content (backward compatibility)
sentences: [{ english: "...", chinese: "...", prononciation: "..." }],
texts: [{ title: "...", content: "...", translation: "..." }],
dialogues: [{ conversation: [...] }]
};
JSON Content Format (New Architecture)
The platform now supports JSON content files for easier editing and maintenance:
{
"name": "Content Name",
"description": "Content description",
"difficulty": "easy|medium|hard",
"vocabulary": {
"word": {
"translation": "French translation",
"prononciation": "pronunciation guide",
"type": "noun|verb|adjective"
}
},
"sentences": [
{
"english": "English sentence",
"chinese": "Chinese translation",
"prononciation": "pronunciation"
}
],
"grammar": { /* grammar rules */ },
"audio": { /* audio content */ },
"exercises": { /* exercise definitions */ }
}
JSON Content Loader Features:
- Automatic transformation from JSON to legacy game format
- Backward compatibility with existing JavaScript content modules
- Support for all rich content features (vocabulary, grammar, audio, exercises)
- Offline-first loading with cloud fallback
Content Adaptivity System
The platform automatically adapts available games and exercises based on content richness:
Content Analysis:
- System scans each content module for available features
- Generates compatibility scores for each game type
- Recommends optimal learning activities
- Handles graceful degradation when content is incomplete
Adaptive Game Selection:
- Rich vocabulary → Enable advanced matching games, pronunciation practice
- Audio files present → Enable listening exercises, pronunciation challenges
- Grammar rules → Enable correction exercises, structured lessons
- Fill-in-blanks data → Enable cloze tests with multiple choice or AI evaluation
- Minimal content → Fall back to basic vocabulary games
Missing Content Handling:
- Display helpful messages: "Add audio files to enable pronunciation practice"
- Suggest content enrichment opportunities
- Gracefully disable incompatible game modes
- Provide content creation tools for missing elements
Example Adaptive Behavior:
// Content with only basic vocabulary
{ vocabulary: { "hello": "你好" } }
→ Enable: Basic matching, simple quiz
→ Disable: Audio practice, grammar exercises
→ Suggest: "Add pronunciation guide and audio for pronunciation practice"
// Rich multimedia content
{ vocabulary: { "hello": { translation: "你好", prononciation: "nǐ hǎo", pronunciation: "audio/hello.mp3" } } }
→ Enable: All vocabulary games, audio practice, pronunciation scoring
→ Unlock: Advanced difficulty levels, speed challenges
🚨 CRITICAL ARCHITECTURE GUIDELINES
NEVER violate these principles to maintain system modularity and maintainability:
🎨 CSS Architecture Rules
-
NEVER modify
css/games.cssfor game-specific styles- Global CSS is only for shared, reusable components
- Game-specific styles MUST be injected by the game itself
-
USE the Global CSS Base System:
// ✅ CORRECT: Use global classes with specific overrides <div class="game-wrapper compact"> // Global base class <div class="game-hud"> // Global HUD structure <div class="game-area"> // Global game area <div class="answer-panel"> // Global answer panel // ✅ CORRECT: Inject game-specific CSS injectCSS() { const styleSheet = document.createElement('style'); styleSheet.textContent = ` .my-game-specific-element { /* Game-only styles */ } `; document.head.appendChild(styleSheet); } -
CSS Classes Hierarchy:
.game-wrapper- Base container (full screen).game-wrapper.compact- Smaller viewport variant.game-hud- Top information bar.game-area- Main play zone.answer-panel- Bottom interaction zone.answer-btn- Interactive buttons
-
❌ FORBIDDEN PATTERNS:
/* ❌ NEVER add game-specific classes to games.css */ .word-storm-wrapper { } .my-game-specific-class { } /* ❌ NEVER hardcode game-specific dimensions in global CSS */ .game-area { height: 600px; } /* This breaks other games */
🎮 Game Development Standards
-
Self-Contained Games:
- Each game MUST inject its own CSS via
injectCSS() - Games MUST use global base classes where possible
- Game-specific elements get their own CSS only
- Each game MUST inject its own CSS via
-
Constructor Pattern (REQUIRED):
class MyGame { constructor({ container, content, onScoreUpdate, onGameEnd }) { this.injectCSS(); // Inject game-specific styles this.init(); // Setup interface } start() { /* Start game logic */ } destroy() { /* Cleanup */ } } -
Module Registration (REQUIRED):
// MUST be at end of game file window.GameModules = window.GameModules || {}; window.GameModules.MyGame = MyGame; -
GameLoader Integration:
- Add game mapping in
game-loader.js→getModuleName() - Add compatibility rules in
content-game-compatibility.js - Add game config in
navigation.js→ game configuration
- Add game mapping in
🔧 Modification Guidelines
When adding new games:
- ✅ Use existing global CSS classes
- ✅ Inject only game-specific CSS
- ✅ Follow constructor pattern
- ✅ Add to GameLoader mapping
When modifying existing games:
- ✅ Keep changes within the game file
- ✅ Don't break global CSS compatibility
- ✅ Test with multiple content types
When adding global features:
- ✅ Add to global CSS base classes
- ✅ Ensure backward compatibility
- ✅ Update this documentation
🚀 Benefits of This Architecture
- Modularity: Each game is self-contained
- Reusability: Base classes work for all games
- Maintainability: Changes don't break other games
- Performance: Only load CSS when game is used
- Scalability: Easy to add new games
⚠️ Common Mistakes to Avoid
CSS Architecture Violations:
/* ❌ DON'T: Adding game-specific styles to games.css */
.word-storm-wrapper { height: 80vh; width: 90vw; }
/* ✅ DO: Use global classes with game-specific injection */
// In game file:
injectCSS() {
// Game-specific overrides only
styleSheet.textContent = `.falling-word { animation: wordGlow 2s; }`;
}
Module Loading Issues:
// ❌ DON'T: Forget GameLoader mapping
// Game won't load because getModuleName() doesn't know about it
// ✅ DO: Add to game-loader.js
const names = {
'my-game': 'MyGame' // Add this mapping
};
HTML Structure Violations:
<!-- ❌ DON'T: Create custom wrapper classes -->
<div class="my-custom-game-wrapper">
<!-- ✅ DO: Use standard global structure -->
<div class="game-wrapper compact">
<div class="game-hud">
<div class="game-area">
<div class="answer-panel">
Integration Checklist:
- Game CSS injected via
injectCSS() - Global classes used for structure
- GameLoader mapping added
- Compatibility rules defined
- Constructor pattern followed
- Module registration at file end
Game Module Format
Game modules must export to window.GameModules with this pattern:
class GameName {
constructor({ container, content, onScoreUpdate, onGameEnd }) {
this.container = container;
this.content = content;
this.onScoreUpdate = onScoreUpdate;
this.onGameEnd = onGameEnd;
}
start() { /* Initialize game */ }
destroy() { /* Cleanup */ }
restart() { /* Reset game state */ }
}
window.GameModules = window.GameModules || {};
window.GameModules.GameName = GameName;
Configuration System
- Main config:
config/games-config.json- defines available games and content - Environment config:
js/core/env-config.js- DigitalOcean Spaces configuration and offline settings - Content discovery: Automatic scanning of both
.jsand.jsoncontent files - Games can be enabled/disabled via
games.{gameType}.enabled - Cloud Integration: DigitalOcean Spaces endpoint configuration for remote content
- Offline-First Strategy: Local content prioritized, remote fallback with timeout protection
- UI settings, scoring rules, and feature flags also in main config
Development Workflow
Running the Application
Open index.html in a web browser - no build process required. All modules load dynamically.
Adding New Games
- Create
js/games/{game-name}.jswith proper module export - Add game configuration to
config/games-config.json - Update
AppNavigation.getDefaultConfig()if needed
Adding New Content
Option 1: JSON Format (Recommended)
- Create
js/content/{content-name}.jsonwith proper JSON structure - Content will be auto-discovered and loaded via JSON Content Loader
- Easier to edit and maintain than JavaScript files
Option 2: JavaScript Format (Legacy)
- Create
js/content/{content-name}.jswith proper module export - Add filename to
ContentScanner.contentFilesarray - Content will be auto-discovered on next app load
Content Creation Tool
- Built-in content creator at
js/tools/content-creator.js - Accessible via "Créateur de Contenu" button on home page
- Generates properly formatted content modules
Key Files by Function
Navigation & Loading:
js/core/navigation.js- SPA navigation controller (452 lines)js/core/game-loader.js- Dynamic module loading (336 lines)js/core/content-scanner.js- Auto content discovery (376 lines)
Content Processing:
js/core/content-engine.js- Content processing engine (484 lines)js/core/content-factory.js- Exercise generation (553 lines)js/core/content-parsers.js- Content parsing utilities (484 lines)js/core/json-content-loader.js- JSON to legacy format transformationjs/core/env-config.js- Environment and cloud configuration
Game Implementations:
js/games/whack-a-mole.js- Standard version (623 lines)js/games/whack-a-mole-hard.js- Difficult version (643 lines)js/games/memory-match.js- Memory pairs game (403 lines)js/games/quiz-game.js- Quiz system (354 lines)js/games/fill-the-blank.js- Sentence completion (418 lines)js/games/text-reader.js- Guided text reading (366 lines)js/games/adventure-reader.js- RPG-style adventure (949 lines)
Important Implementation Details
Scoring System
- Games call
this.onScoreUpdate(score)to update display - Final scores saved to localStorage with key pattern:
score_{gameType}_{contentType} - Best scores tracked and displayed in game-end modal
- Points per correct answer, malus per error, speed bonus
- Score history and achievement badges
Content Compatibility
ContentScannerevaluates content compatibility with each game type- Compatibility scoring helps recommend best content for each game
- Games should handle various content formats gracefully
Memory Management
GameLoader.cleanup()called before loading new games- Games should implement
destroy()method for proper cleanup - Previous game instances must be cleaned up to prevent memory leaks
Error Handling
- Content loading errors logged but don't crash the application
- Fallback mechanisms for missing content or games
- User-friendly error messages via
Utils.showToast()
Design Guidelines
Visual Design Principles
- Modern, clean design optimized for children (8-9 years old)
- Large, tactile buttons (minimum 44px for touch interfaces)
- High contrast colors for accessibility
- Smooth, non-aggressive animations
- Emoji icons combined with text labels
Color Palette
- Primary: Blue (#3B82F6) - Trust, learning
- Secondary: Green (#10B981) - Success, validation
- Accent: Orange (#F59E0B) - Energy, attention
- Error: Red (#EF4444) - Clear error indication
- Neutral: Gray (#6B7280) - Text, backgrounds
Accessibility Features
- Full keyboard navigation support
- Alternative text for all images
- Adjustable font sizes
- High contrast mode compatibility
- Screen reader friendly markup
Responsive Design
- Mobile/tablet adaptation
- Touch-friendly interface
- Portrait/landscape orientation support
- Fluid layouts that work on various screen sizes
- Fixed Top Bar: App title and network status always visible
- Network Status: Automatic hiding of status text on mobile devices
- Content Margin: Proper spacing to accommodate fixed header
Git Configuration
Repository
- Remote: Bitbucket repository at
AlexisTrouve/class-generator-system - Port 443 Configuration: Git is configured to use SSH over port 443 for network restrictions
- Remote URL:
ssh://git@altssh.bitbucket.org:443/AlexisTrouve/class-generator-system.git
SSH Configuration
To push to the repository through port 443, the following SSH configuration is required in ~/.ssh/config:
Host altssh.bitbucket.org
HostName altssh.bitbucket.org
Port 443
User git
IdentityFile ~/.ssh/bitbucket_key
Push Commands
- Standard push:
git push - Set upstream:
git push --set-upstream origin master
🚨 Developer Guidelines & Common Pitfalls
Critical information for future developers to avoid common mistakes and maintain code quality.
🔥 Template Literals Syntax Errors
MOST COMMON BUG - Always check this first:
// ❌ FATAL ERROR - Will break entire module
styleSheet.textContent = \`css here\`; // Backslash = SyntaxError
// ✅ CORRECT
styleSheet.textContent = `css here`; // Backtick (grave accent)
How to debug:
# Test syntax before browser testing
node -c js/games/your-game.js
# Look for "Invalid or unexpected token" errors
# Usually points to template literal issues
🎮 Game Development Best Practices
Required Game Structure:
class NewGame {
constructor({ container, content, onScoreUpdate, onGameEnd }) {
this.injectCSS(); // CSS injection FIRST
this.extractContent(); // Content processing
this.init(); // UI initialization
}
start() {
// Separate start method - NOT in constructor
this.startGameLogic();
}
destroy() {
// Cleanup intervals, event listeners, injected CSS
this.cleanup();
}
}
// REQUIRED: Global module registration
window.GameModules = window.GameModules || {};
window.GameModules.NewGame = NewGame;
CSS Architecture - Zero Tolerance Policy:
// ✅ CORRECT: Inject game-specific CSS
injectCSS() {
if (document.getElementById('my-game-styles')) return; // Prevent duplicates
const styleSheet = document.createElement('style');
styleSheet.id = 'my-game-styles';
styleSheet.textContent = `
.my-game-element { color: red; }
.falling-word { animation: myCustomAnimation 2s; }
`;
document.head.appendChild(styleSheet);
}
// ❌ FORBIDDEN: Modifying css/games.css for game-specific styles
// css/games.css should ONLY contain global reusable classes
🔍 Debug Templates for Quick Testing
Isolated Game Testing:
<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"></head>
<body>
<div id="container" style="width:800px; height:600px; border:1px solid #ccc;"></div>
<script>
window.logSh = (msg, level) => console.log(`[${level}] ${msg}`);
window.Utils = { storage: { get: () => [], set: () => {} } };
window.GameModules = {};
window.ContentModules = {};
</script>
<script src="js/content/your-content.js"></script>
<script src="js/games/your-game.js"></script>
<script>
try {
const game = new window.GameModules.YourGame({
container: document.getElementById('container'),
content: window.ContentModules.YourContent,
onScoreUpdate: score => console.log('Score:', score),
onGameEnd: score => console.log('Game ended:', score)
});
if (game.start) game.start();
console.log('✅ Game loaded successfully!');
} catch (error) {
console.error('❌ Error:', error.message);
}
</script>
</body>
</html>
🌐 Interface Language Standards
All UI text must be in English:
// ✅ CORRECT
"Score: ${score}"
"Lives: ${lives}"
"Level Up!"
"Game Over"
"Back to Games"
// ❌ FORBIDDEN
"Score: ${score} points" // French
"Vies: ${lives}" // French
"Niveau supérieur!" // French
📋 Integration Checklist
Before committing any new game:
- ✅ Syntax check:
node -c js/games/your-game.js - ✅ CSS injected via
injectCSS()method - ✅ No modifications to
css/games.css - ✅ Uses global classes:
.game-wrapper,.game-hud,.game-area,.answer-panel - ✅ GameLoader mapping added in
getModuleName() - ✅ Navigation config updated in
navigation.js - ✅ Constructor pattern followed exactly
- ✅ Module export at end of file
- ✅ English-only interface text
- ✅ Isolated test file created and working
⚡ Performance & Architecture Notes
Current System Architecture:
- CSS: Global base classes + per-game injection
- Content: Auto-discovery + JSON/JS dual support
- Navigation: URL-based SPA with dynamic loading
- Modules: Dynamic import + backward compatibility
Critical Files (DO NOT BREAK):
js/core/game-loader.js- Module name mappingcss/games.css- Global CSS base (game-agnostic only)js/core/navigation.js- Game configuration and routing
🔧 Common Debugging Commands
# Check file syntax
node -c js/games/your-game.js
# Check for non-ASCII characters (encoding issues)
grep -P '[^\x00-\x7F]' js/games/your-game.js
# Find template literal issues
grep -n "\\\`" js/games/your-game.js
# Test local server
python3 -m http.server 8000
# Then: http://localhost:8000/?page=play&game=your-game&content=available-content
🚀 Quick Win Tips
- Copy working game structure - Use existing games as templates
- Test isolated first - Don't debug through the full app initially
- Check browser console - JavaScript errors are usually obvious
- Verify content compatibility - Make sure your content has the data your game needs
- Use global CSS classes - Don't reinvent layout, build on existing structure
Remember: Most bugs are simple syntax errors (especially template literals) or missing module registrations. Check these first! 🎯