Atlas: Infrastruktur + Team-Konventionen + Sprachregel Lernarbeit

- Design-System (assets/css/design-system.css) mit 21 Komponenten,
  iPad-Responsive-Breakpoints, Touch-Ziele 36px, Music-Player,
  Glossar-Tooltips
- Templates (sims/template.html + student/teacher-Dashboard)
- Docs: module-interface.md (inkl. 4a Sprachregel, 4b Leichte Sprache,
  4c iPad), content-architecture.md, crash-recovery.md, music-registry.md
- Admin-Infrastruktur: admin-modules.html + api/admin-modules.php
  (Titel, Emoji, Bild, Status, Dauer, Alter pro Modul)
- Inbox-System: _inbox/README.md + _status.md fuer Atlas + Briefings
  an Klima, Glossar, Lehrplan, Fluss
- Zentrale SFX-Pipeline (scripts/generate-sounds.py)
- DALL-E-Bilder: 8 Badges + 5 Glossar-Repraesentationsbilder (Querformat)
- Logo + Inter-Font lokal
- PHP-APIs: admin, glossar, levels, licenses, progress, waypoints,
  assignments, profile, tickets
- Spielsprache entfernt (admin-modules, admin-levels, schueler)
- Landing-Page-Bearbeitungen (Boote sichtbarer, Button-Hintergrund)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-19 11:51:14 +02:00
parent 2136bbbe62
commit 9a61f55cb1
134 changed files with 1012826 additions and 690 deletions
+618
View File
@@ -0,0 +1,618 @@
# GeoGraSim — Module Interface Specification
Dieses Dokument definiert die Schnittstellen zwischen der Lernplattform und den einzelnen Simulationsmodulen. Jede Modul-Instanz (Claude Code Session) bekommt dieses Dokument als Kontext.
---
## 1. Architektur-Überblick
```
Lernplattform (PHP + MySQL) Simulationsmodul (HTML/JS/Canvas)
───────────────────────────── ─────────────────────────────────
Authentifizierung & Sessions → Spieler-Kontext (wer, welches Level)
Modul-Freigabe pro Klasse → Zugang ja/nein
Level-Konfiguration → Schwierigkeitsparameter
← Live-Fortschritt (während Spiel)
← Achievements (Badges, Sterne)
← Reflexionsantworten
← Abschluss-Assessment
Detail-View (Schüler) ← Modulspezifische Ergebnis-Daten
Detail-View (Lehrer) ← Aktionslog + Metriken
Summary-Kachel ← Standardisierte Zusammenfassung
```
---
## 2. Einbettung: PHP-Page pro Modul
Jedes Modul wird über eine PHP-Seite ausgeliefert: `App/pages/{modul-id}.php`
Die PHP-Seite:
1. Prüft die Session (Schüler oder Gast)
2. Lädt Level-Konfiguration aus der DB
3. Injiziert den Spieler-Kontext als JavaScript-Objekt
4. Lädt die HTML-Datei des Moduls (Template-Replacement oder direktes PHP)
### Spieler-Kontext (PHP → JS)
```html
<script>
window.__GGS__ = {
// Session
sessionId: '<?= $_SESSION["student_session"] ?? "" ?>',
studentId: <?= $_SESSION['student_id'] ?? 'null' ?>,
studentName: '<?= addslashes($_SESSION["student_name"] ?? "Gast") ?>',
classId: <?= $_SESSION['class_id'] ?? 'null' ?>,
// Modul
simId: 'klima', // eindeutige Modul-ID
simName: 'Klimawächter', // Anzeigename
level: 1, // aktuelles Level (1, 2, 3)
// Level-Konfiguration (aus DB: game_levels)
levelConfig: {
difficulty: 'easy',
timeLimit: 75, // Runden/Ticks
startBudget: 200,
eventFrequency: 0.3,
// ... modulspezifische Parameter
},
// Vorheriges Ergebnis (falls vorhanden)
previousScore: null, // oder {stars: 3, score: 72, ...}
// URLs
baseUrl: '/geograsim/App', // oder '' bei geograsim.at
apiUrl: '/geograsim/App/php/api'
};
</script>
```
---
## 3. API-Endpunkte (JS → PHP)
Alle API-Calls gehen an `{apiUrl}/{endpoint}.php` via `fetch()` mit JSON body.
### 3.1 Live-Fortschritt melden
```
POST /php/api/progress.php
{
"session_id": "uuid",
"sim_id": "klima",
"action": "update",
"data": {
"level": 1,
"phase": "playing", // "tutorial", "playing", "paused", "finished"
"tick": 34, // aktueller Spielfortschritt
"tick_max": 75, // maximale Ticks
"score_so_far": 45, // Zwischenstand (0100)
"metrics": { // modulspezifische Metriken
"co2": 780,
"temperature": 1.1,
"budget": 145
}
}
}
```
**Wann aufrufen:** Alle 10 Ticks oder bei wichtigen Ereignissen. Nicht bei jedem Tick — das wäre zu viel Traffic.
### 3.2 Achievement melden
```
POST /php/api/progress.php
{
"session_id": "uuid",
"sim_id": "klima",
"action": "achievement",
"data": {
"level": 1,
"badge_key": "first_windpark", // eindeutiger Key
"badge_name": "Windkraft-Pionier", // Anzeigename
"badge_icon": "🌬️", // Emoji
"badge_desc": "Ersten Windpark gebaut",
"xp": 50 // XP-Belohnung
}
}
```
### 3.3 Reflexionsantwort speichern
```
POST /php/api/progress.php
{
"session_id": "uuid",
"sim_id": "klima",
"action": "reflection",
"data": {
"level": 1,
"question": "Was war deine wirksamste Entscheidung?",
"answer": "Windpark gebaut",
"answer_index": 0, // Index der gewählten Option
"options": ["Windpark gebaut", "Küstenschutz ausgebaut", "Verkehr reduziert", "Ich bin mir nicht sicher"]
}
}
```
### 3.4 Abschluss-Assessment
```
POST /php/api/progress.php
{
"session_id": "uuid",
"sim_id": "klima",
"action": "submit_assessment",
"data": {
"level": 1,
"stars": 3, // 15
"score": 72, // 0100 (Gesamtbewertung)
"duration_ms": 324000, // Spielzeit in Millisekunden
"completed": true, // Level geschafft?
// Modulspezifische Ergebnisse
"results": {
"final_co2": 580,
"final_temperature": 1.3,
"final_budget": 42,
"final_flooded_pct": 12,
"renewable_pct": 78,
"measures_bought": 8,
"events_survived": 5
},
// Aktionslog (für Lehrer-Detailansicht)
"action_log": [
{"tick": 3, "action": "buy", "item": "windpark", "cost": 25},
{"tick": 5, "action": "buy", "item": "solar", "cost": 18},
{"tick": 8, "action": "buy", "item": "deich", "cost": 30},
{"tick": 12, "action": "event", "type": "sturmflut", "result": "survived"},
// ...
],
// Entscheidungseffizienz (automatisch berechenbar)
"efficiency": {
"score_per_action": 9.0, // score / anzahl_aktionen
"budget_efficiency": 0.71 // ergebnis / ausgegebenes_budget
},
// Badges verdient in diesem Level
"badges_earned": ["first_windpark", "coastal_defense"]
}
}
```
---
## 4. Summary-Format (für Klassenübersicht)
Jedes Modul liefert nach Abschluss eines Levels eine standardisierte Zusammenfassung. Die Plattform rendert daraus einheitliche Kacheln.
```json
{
"sim_id": "klima",
"sim_name": "Klimawächter",
"sim_icon": "🌍",
"level": 1,
"stars": 3,
"score": 72,
"completed": true,
"duration_formatted": "5:24",
"key_metric": {
"label": "Endtemperatur",
"value": "+1.3 °C",
"status": "warning"
},
"badges_count": 2
}
```
---
## 4a. Sprache — Lernarbeit statt Spielsprache (PFLICHT)
GeoGraSim ist kein Spiel, sondern eine **Simulations-Lernumgebung**.
Alle sichtbaren UI-Texte folgen dem Prinzip: **Lernarbeit**, nicht
Unterhaltung.
### Bildungstheoretischer Hintergrund
- **Wygotski**: Lernen als aktive Konstruktion in der Zone der nächsten
Entwicklung
- Sprache formt Haltung: "Spiel" → abschalten dürfen. "Arbeit" →
ernstgenommen werden.
- Gegenüber Eltern, Schulleitung, Lehrplan-Koordinator:innen:
"Simulation" ist verteidigungsfähig, "Spiel" nicht.
### Lexikon (verbindlich)
| NICHT verwenden | STATTDESSEN |
|-------------------------|---------------------------------------------|
| spielen, Spiel | arbeiten mit, Simulation, bearbeiten |
| Weiterspielen | Fortsetzen, weiterarbeiten |
| "Jetzt spielen" | "Simulation starten", "Los arbeiten" |
| Spielstand | Arbeitsstand, Fortschritt |
| Spieler:in | Lernende, Bearbeiter:in |
| Spielrunde | Durchgang, Arbeitsphase |
| Gameplay | Simulationsablauf, Arbeitsweise |
| "verloren", "Game Over" | "Ziel verfehlt", "Durchgang beendet" |
| Highscore | Beste Leistung, Bestwert |
| Level | OK (pädagogisch vertretbar), besser "Schwierigkeit" oder "Stufe" |
### Ausnahmen
- **Interne Variablen-/Tabellennamen** (`game.tick`, `gameState`,
`game_saves`, `game_levels`) sind weiterhin OK — nicht sichtbar,
keine pädagogische Wirkung.
- **Sichtbare UI-Texte**, **Marketing-Inhalte**, **Dokumentation für
Endnutzer** folgen strikt der Lexikon-Regel.
### Anwendung bei deinem Modul
- Prüfe bei jeder neuen UI-Zeile, bei jedem Overlay-Titel, bei jedem
Button-Text: Kommt "spielen" oder ein verwandtes Wort vor?
- Beim Übernehmen von V1-Texten: V1-Wortwahl korrigieren, nicht
1:1 kopieren.
- Tutorial-Karten, Achievements, Endscreen, Reflexionsfragen: besonders
sensibel, weil prominent sichtbar.
### Beispiele aus der Praxis
| Vorher (typisch V1) | Nachher (V2) |
|----------------------------------------|---------------------------------------|
| "Willkommen zum Klimaspiel!" | "Willkommen zur Klima-Simulation." |
| "Spiel starten" | "Simulation starten" |
| "Speichern & weiterspielen" | "Speichern & fortsetzen" |
| "Du hast gewonnen! 🏆" | "Ziel erreicht! 🏆" |
| "Game Over" | "Durchgang beendet" |
| "Dein Spielstand wird geladen ..." | "Dein Arbeitsstand wird geladen ..." |
| "Schwierigkeitsgrad wählen" | ok, oder "Stufe wählen" |
| "Dein Highscore" | "Deine beste Leistung" |
---
## 4b. Leichte Sprache (Barrierefreiheit, Inklusion)
Die Lehrperson kann pro Schüler:in in der Klassenliste den Flag
**"Leichte Sprache"** aktivieren. Wenn gesetzt, werden Texte im gesamten
System (Glossar-Tooltips, Beispiele, Modul-Beschreibungen, Info-Topics)
in vereinfachter Sprache ausgeliefert.
### Schüler-Flag in der DB
```sql
students.easy_language BOOLEAN NOT NULL DEFAULT 0
```
Setzen via:
```
POST /api/students {action: "update", studentId: N, easyLanguage: true}
```
### Was automatisch in Easy übersetzt wird (Backend-API)
| Tabelle | Normal-Spalte | Easy-Spalte |
|---|---|---|
| `glossar` | `short`, `text` | `short_easy`, `text_easy` |
| `glossar_examples` | `text` | `text_easy` |
| `module_info` | `short_desc`, `long_desc`, `learning_goals` | `short_desc_easy`, `long_desc_easy`, `learning_goals_easy` |
**Fallback-Logik:** Wenn die Easy-Spalte leer ist, liefert die API die
Normal-Version. So bricht nichts, wenn noch nicht alles übersetzt wurde.
### API-Verhalten
Die Glossar-API (`/api/glossar.php`) erkennt den aktiven Schüler automatisch
über die Session und liefert dann die Easy-Variante. Keine zusätzlichen
Parameter nötig.
Optional zum Testen / expliziten Überschreiben:
- `?easy=1` → erzwingt Easy
- `?easy=0` → erzwingt Normal
Response enthält ein Meta-Feld `_easy: true|false`, damit das Frontend
optional einen Hinweis "In leichter Sprache" einblenden kann.
### Wer schreibt die Easy-Versionen
- **Glossar-Instanz** schreibt `short_easy`, `text_easy`, `text_easy`
(Examples) für alle Glossar-Einträge
- **Lehrplan-Instanz** schreibt `*_easy` für `module_info`
- **Modul-Instanzen** schreiben eigene Event-Info-Topics direkt mit einer
Easy-Variante (wenn sie Info-Topics haben)
### Merkregeln für "Leichte Sprache"
- Kurze Sätze (max. ~1012 Wörter)
- Häufige, einfache Wörter
- Aktiv statt Passiv
- Fremdwörter vermeiden oder erklären
- Zahlen als Ziffern, nicht ausgeschrieben
- Keine Metaphern, keine Ironie
- Hauptaussage an den Anfang
### Richtlinien als Inspiration
- Netzwerk Leichte Sprache: https://www.leichte-sprache.org/
- capito Leichte Sprache Standards (A1 / A2 / B1)
---
## 4c. Referenzgerät — iPad Landscape (1180×820)
**iPad ist unser Hauptreferenzgerät.** Schulen in Österreich und DACH setzen
überwiegend iPads ein. Jedes Modul muss auf iPad Landscape wunderbar funktionieren.
### Layout-Breiten (aus design-system.css, automatisch)
| Viewport | Links | Canvas | Rechts |
|---|---|---|---|
| Desktop ≥1200px | 240px | 1fr | 280px |
| **iPad Landscape 9001199px** | **210px** | **1fr** | **250px** |
| iPad Portrait / Mobil <900px | einspaltig, Panels unter Canvas | | |
Die Breakpoints sind im Design-System gesetzt — Module müssen nichts dafür tun,
wenn sie `.ggs-sim-layout` verwenden.
### Pflichten für alle Module
**Touch-Ziele:** Alle Buttons, Cards und klickbaren Elemente mindestens
36×36px (idealerweise 40×40). Das ist in `.ggs-speed-btn`, `.ggs-btn-*`,
`.ggs-card` bereits so gesetzt. Eigene klickbare Elemente bitte auch so
dimensionieren.
**Kein Hover-Abhängigkeit:** Hover-Effekte sind schön, aber auf iPad gibt es
keinen Cursor. Jede Funktion, die per Hover erreichbar ist, muss auch per
Tap funktionieren. Hover ist Bonus, nicht Pflicht-UX. Im Design-System sind
Hover-Effekte schon in `@media (hover: hover)` gekapselt — Cards zeigen auf
Touch einen `:active`-Zustand statt klebendem Hover.
**Scrolling im Canvas:** Wenn das Canvas per Drag interagiert (3D-Orbit, Map-
Pan), muss verhindert werden, dass iPad Safari stattdessen die Page scrollt:
`touch-action: none` auf dem Canvas-Element setzen. Für Canvas-Zonen ohne
Drag-Interaktion nicht nötig.
**Kein Double-Tap-Zoom im Body:** Bereits im Design-System gesetzt
(`touch-action: manipulation` auf body). Kein Bedarf, das pro Modul zu
ändern — ausser du willst Pinch-to-zoom für ein spezielles Element
erlauben.
**Formular-Eingaben (Reflexion, Textfelder):** `font-size: 16px` mindestens,
sonst zoomt iPad Safari beim Fokus rein. Das Design-System setzt das für
Standardfelder bereits.
### Was noch zu testen ist
- Graph-Zoom per Tap: funktioniert
- Card-Tap: funktioniert, kein Hover-Kleber
- Speed-Buttons: gross genug
- Overlay-Schließen per Tap außerhalb: funktioniert
- Glossar-Tooltip per Tap öffnet, zweiter Tap außerhalb schließt: ✓
- Dropdown-Menüs (z.B. Country-Picker, falls im Header): Select statt
Custom-Dropdown, weil iPad native Selects perfekt rendert
---
## 5. Design-System
Alle Module binden `assets/css/design-system.css` ein. Diese Datei definiert:
### Farb-Variablen (Pflicht)
```css
--ggs-fjord /* Primärblau */
--ggs-moss /* Erfolg/Grün */
--ggs-sand /* Kosten/Neutral */
--ggs-coral /* Gefahr/Rot */
--ggs-orange /* Warnung */
```
### Layout-Zonen (verwende diese Klassen)
```
.ggs-header → App-Header (Logo + Textlogo + Separator + Modulname)
.ggs-sim-layout → 3-Spalten Grid (Standard: Canvas in der Mitte)
.ggs-sim-layout.fullscreen → Canvas randlos, Panels als Glass-Overlays darüber
.ggs-zone-status → Links: Parameter, Ziele, Badges
.ggs-zone-sim → Mitte: Canvas/3D/Karte
.ggs-zone-actions → Rechts: Maßnahmen/Werkzeuge/Missionen
.ggs-zone-graphs → Unten: Zeitverlaufs-Graphen (klickbar zum Vergrössern)
.ggs-event-viewport → In-Canvas Notifications (erscheinen gross, verschwinden)
.ggs-event-stack → Event-Stapel links unten (aufklappbar)
.ggs-loading → Ladebildschirm mit drehendem Logo
```
### UI-Komponenten (verwende diese Klassen)
```
.ggs-card → Auswahl-Card (Maßnahme, Werkzeug, Mission)
.ggs-param → Parameter-Anzeige mit Balken
.ggs-graph-card → Zeitverlaufs-Graph (SVG)
.ggs-event → Event-Pill im Feed
.ggs-speed → Geschwindigkeits-Buttons
.ggs-overlay → Modal/Overlay (Tutorial, Level-Ende, Endscreen)
.ggs-stars → Sterne-Bewertung
.ggs-toast → Achievement-Toast
.ggs-btn → Button (primary, secondary, ghost, success, danger)
.ggs-badge → Mini-Badge (cost, effect, protect, level-easy/medium/hard)
.ggs-phases → Phasen-Dots im Header
```
### Template-Datei
`App/sims/template.html` enthält alle Zonen mit Platzhalter-Inhalten und minimalen JS-Helfern:
- `showOverlay(id)` / `hideOverlay(id)`
- `showAchievement(icon, title, subtitle)` — Toast oben rechts
- `showEvent(icon, text, type)` — Notification im Canvas + Stapel (type: 'good'/'bad'/'neutral')
- `toggleEventStack()` — Event-Stapel auf/zuklappen
- `updateGraph(index, points, currentValue)` — Klick auf Graph vergrössert
- `updateParam(index, value, percent, trend)`
- `reportProgress(data)`
- `submitAssessment(results)`
- `submitReflection(level, question, answer)`
---
## 6. Modul-IDs
| ID | Name | Status |
|----|------|--------|
| `klima` | Klimawächter (2D + 3D) | Aktiv |
| `fluss` | Flussmanagement | Aktiv |
| `heli` | Heli-Navigation | Aktiv |
| `stadt` | Stadt & Raumplanung | In Entwicklung |
| `regenwald` | Regenwald-Expedition | Überarbeitung nötig |
---
## 7. Datenbank-Tabellen
### Gemeinsam (Plattform verwaltet)
- `teachers`, `classes`, `students` — Benutzerverwaltung
- `student_sessions` — Anonyme Sessions
- `game_levels` — Level-Konfiguration pro Modul × Schwierigkeit
- `player_progress` — XP, Level-Stand, Badges
- `assessment_answers` — Reflexionsantworten
- `class_modules` — Modul-Freigabe pro Klasse
- `licenses` — Lizenz-System
### Modulspezifisch (Modul verwaltet)
- `game_saves` — Spielstände (session_id + save_key)
- `assessments` — Detaillierte Ergebnisdaten (JSON-Felder)
- Module können eigene Tabellen anlegen (z.B. `geo_waypoints` für Heli)
---
## 7b. Persistenz-Pflicht: Autosave und Resume
**Kernprinzip:** Ein Browser-Reload (F5, Tab-Wechsel, Stromausfall, Schüler schliesst aus Versehen das Fenster) darf **niemals** zum Neustart des Spiels führen. Der Schüler muss dort weitermachen können, wo er aufgehört hat.
### Was das bedeutet
- Beim **Seitenaufruf / Reload** lädt das Modul den letzten gespeicherten Stand und setzt genau dort fort (gleiche Runde, gleiche Werte, gleiche platzierte Massnahmen, gleicher CO₂-Stand, etc.).
- Bei **Klick auf Reset** (und nur dann!) wird der Spielstand gelöscht und das Spiel beginnt von vorne.
- **Autosave** nach jeder wichtigen Aktion (Tick-Ende, Kauf einer Massnahme, Level-Übergang). Kein manuelles "Speichern"-Knopfdrücken nötig.
### Wie
Zwei Speicher, in dieser Reihenfolge:
1. **localStorage** (Primär): Sofortiges, synchrones Speichern im Browser. Funktioniert auch offline.
- Schlüssel-Format: `ggs-save-{modul-id}-{level}` (z.B. `ggs-save-klima-2`)
- Wert: JSON-Serialisierung des Spielzustands
2. **Server-Backup** (Sekundär, bei vorhandener Session): Zusätzlich per POST an `/api/saves.php` schicken, damit der Fortschritt auf anderen Geräten verfügbar ist. Fällt das Netz aus, ist localStorage der Fallback.
### Konkrete Implementierung
```javascript
// Speichern
function autoSave() {
const state = game.serialize(); // dein kompletter Spielzustand
const key = `ggs-save-klima-${game.level}`;
try { localStorage.setItem(key, JSON.stringify(state)); } catch {}
// Optional: Server-Spiegelung
if (window.__GGS__.sessionId) {
fetch(window.__GGS__.apiUrl + '/saves.php', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
sim_id: 'klima',
save_key: `level-${game.level}`,
save_data: state
})
}).catch(() => {});
}
}
// Laden beim Start
function loadOrInit() {
const key = `ggs-save-klima-${level}`;
const raw = localStorage.getItem(key);
if (raw) {
try {
game.deserialize(JSON.parse(raw));
showEvent('💾', 'Spielstand geladen — weiter bei Runde ' + game.tick, 'neutral');
return;
} catch {}
}
// Fallback: neues Spiel
game.init();
}
// Reset-Knopf
function resetGame() {
if (!confirm('Fortschritt wirklich löschen und neu starten?')) return;
localStorage.removeItem(`ggs-save-klima-${game.level}`);
// Auch Server-Save löschen (DELETE), falls Session vorhanden
game.init();
}
```
### Wann speichern?
- Nach jedem Tick/Runden-Ende (automatisch)
- Nach jedem Kauf/Aktion (automatisch)
- Nach jeder Reflexionsantwort (automatisch)
- Bei Phasenwechsel (Tutorial → Spiel, Level → Level)
- Vor `beforeunload` als Sicherheit (falls Tab geschlossen wird)
### Welche Daten gehören in den Save
Alles, was der Spieler getan hat oder was sich durch Spielverlauf geändert hat:
- Aktuelle Runde / Tick
- Aktuelles Level
- Alle Spielparameter (Budget, CO₂, Temperatur, etc.)
- Gekaufte / platzierte Massnahmen inkl. Position
- Absolvierte Achievements / Badges
- Tutorial-Fortschritt (welche Schritte sind durch)
- Event-Historie (falls didaktisch relevant)
### UI-Hinweise
- Beim Laden eines bestehenden Stands: kurze Info einblenden ("Spielstand geladen — weiter bei Runde 34")
- Reset-Button (🔄) sichtbar im Header, mit Bestätigungsdialog ("Fortschritt löschen?")
- Save-/Load-Buttons im Header sind optional (für explizites Speichern) — Autosave passiert ohnehin
### Warum das wichtig ist
Didaktisch: Schüler:innen arbeiten in 45-Minuten-Einheiten. Wird das Modul aus Zeitgründen unterbrochen, soll in der nächsten Stunde dort weitergespielt werden können. Ohne Persistenz wäre das Modul unterrichtstauglich nur bei 100%-Fertigstellung in einer Einheit — unrealistisch.
Technisch: Browser-Crashs, versehentliche Reloads, Netzausfälle — alles passiert. Ohne Autosave verliert der Schüler seine Arbeit und frustriert sich. Ein Tabubruch im Lernkontext.
---
## 8. Datei-Struktur pro Modul
```
App/sims/{modul-id}/
├── game.html ← Hauptdatei (oder Template für PHP-Injection)
├── start.html ← Optional: Mini-Game (iframe)
├── landing.html ← Optional: Mini-Game (iframe)
└── assets/ ← Modul-eigene Assets (Sounds, Bilder)
App/pages/
├── {modul-id}.php ← PHP-Wrapper (Session, DB, Kontext-Injection)
└── {modul-id}-game.php ← Optional: Wenn Hauptseite DB-Daten braucht
```
---
## 9. Checkliste für neue Module
- [ ] Design-System CSS eingebunden
- [ ] Einheitlicher Header mit Logo, Modulname, Level-Badge
- [ ] Layout nutzt `ggs-sim-layout` Zonen
- [ ] Action-Cards nutzen `ggs-card` Klasse
- [ ] Parameter nutzen `ggs-param` mit Farbstufen
- [ ] Graphen nutzen `ggs-graph-card` (mindestens 1)
- [ ] Event-Feed zeigt Spielereignisse
- [ ] Speed-Control vorhanden (falls zeitbasiert)
- [ ] Tutorial-Overlay beim ersten Start
- [ ] Between-Level Screen mit Sterne + Reflexionsfrage
- [ ] Endscreen mit Stats-Grid
- [ ] Achievement-Toasts bei Meilensteinen
- [ ] API: `reportProgress()` alle 10 Ticks
- [ ] API: `showAchievement()` + POST bei Badge
- [ ] API: `submitAssessment()` bei Level-Ende
- [ ] API: `submitReflection()` bei Level-Übergang
- [ ] PHP-Page erstellt mit `window.__GGS__` Kontext
- [ ] **Autosave nach jeder Aktion** (localStorage + optional Server)
- [ ] **Resume beim Reload** (lädt letzten Stand, kein Neustart)
- [ ] **Reset-Button** löscht Save und startet neu (mit Bestätigungsdialog)