┌─────────────────────────────────────────────────────────────────┐
│ Browser (Client) │
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────────┐ │
│ │ i18n.js │ │ scenarios.js│ │ causes.js │ │
│ │ │ │ │ │ │ │
│ │ Language │ │ Scenario │ │ Failure cause │ │
│ │ strings & │ │ definitions │ │ definitions & │ │
│ │ toggle │ │ & metadata │ │ explanations │ │
│ └──────┬──────┘ └──────┬──────┘ └───────────┬─────────────┘ │
│ │ │ │ │
│ └────────────────┼─────────────────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ evaluator.js │ │
│ │ │ │
│ │ • Evaluate selections │ │
│ │ • Calculate plausib. │ │
│ │ • Generate feedback │ │
│ └───────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ ui.js │ │
│ │ │ │
│ │ • Render scenarios │ │
│ │ • Handle selections │ │
│ │ • Display feedback │ │
│ │ • Manage language UI │ │
│ └───────────┬───────────┘ │
│ │ │
│ ▼ │
│ ┌───────────────────────┐ │
│ │ app.js │ │
│ │ │ │
│ │ • Initialize modules │ │
│ │ • Coordinate flow │ │
│ │ • State management │ │
│ └───────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
Purpose: Manage all translatable text content and language switching.
Responsibilities:
- Store all UI strings in German and English
- Provide
t(key)function to retrieve translated strings - Handle language toggle (DE ↔ EN)
- Persist language preference in localStorage
- Emit language change events for UI updates
Exports:
t(key, params?)– Get translated stringsetLanguage(lang)– Switch languagegetLanguage()– Get current languageonLanguageChange(callback)– Register listener
Purpose: Define and manage all educational scenarios.
Responsibilities:
- Store scenario definitions (band, time, distance, antenna, symptoms)
- Map scenarios to relevant failure causes with plausibility ratings
- Provide scenario retrieval functions
- Support scenario categories/difficulty levels (future)
Exports:
getAllScenarios()– List all scenariosgetScenarioById(id)– Get specific scenariogetScenarioCount()– Total number of scenarios
Purpose: Define all possible failure causes with explanations.
Responsibilities:
- Define failure cause catalog
- Store beginner-friendly explanations (DE/EN)
- Categorize causes (propagation, equipment, interference, operator)
- Provide cause metadata for UI rendering
Exports:
getAllCauses()– List all causesgetCauseById(id)– Get specific causegetCausesByCategory(category)– Filter by category
Purpose: Analyze player selections and generate feedback.
Responsibilities:
- Compare selected causes against scenario's plausibility map
- Generate structured feedback (plausible/unlikely/missed)
- Produce beginner-friendly explanations
- NO scoring – only educational feedback
Exports:
evaluate(scenarioId, selectedCauseIds)– Main evaluation function- Returns:
{ plausible: [], unlikely: [], missed: [], explanations: {} }
Purpose: Render all visual elements and handle user interactions.
Responsibilities:
- Render scenario cards with all information
- Display cause selection checkboxes
- Show/hide feedback panels
- Handle language toggle button
- Manage navigation between scenarios
- Apply accessibility best practices
Exports:
renderScenario(scenario)– Display scenariorenderCauseSelection(causes)– Show checkboxesrenderFeedback(evaluation)– Display resultsupdateLanguage()– Refresh all text
Purpose: Initialize and coordinate all modules.
Responsibilities:
- Bootstrap application on page load
- Manage application state (current scenario, selections)
- Coordinate module interactions
- Handle scenario navigation
Exports:
init()– Start applicationnextScenario()– Advance to nextresetScenario()– Clear current selections
1. User loads page
└─► app.init()
└─► i18n.setLanguage(stored || 'de')
└─► ui.renderScenario(scenarios[0])
└─► ui.renderCauseSelection(causes)
2. User selects causes and clicks "Check"
└─► app.checkSelection()
└─► evaluator.evaluate(scenarioId, selectedIds)
└─► ui.renderFeedback(result)
3. User toggles language
└─► i18n.setLanguage(newLang)
└─► ui.updateLanguage()
└─► ui.renderFeedback() (if visible)
4. User clicks "Next Scenario"
└─► app.nextScenario()
└─► ui.renderScenario(nextScenario)
└─► ui.clearFeedback()
- Separation of Concerns: Text content is completely separate from logic
- No Backend Required: All data is embedded; works offline
- Deterministic Evaluation: Same inputs always produce same feedback
- Extensibility: New scenarios/causes can be added without code changes
- Accessibility: Semantic HTML, keyboard navigation, screen reader support
- Mobile-First: Responsive design for all screen sizes