# 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 ``` --- ## 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 (0–100) "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, // 1–5 "score": 72, // 0–100 (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. ~10–12 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 900–1199px** | **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)