- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/ - 12 code-workspace-Files - STATUS-*.md - viele M/D/R-Änderungen an bereits getrackten Files - .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
22 KiB
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:
- Prüft die Session (Schüler oder Gast)
- Lädt Level-Konfiguration aus der DB
- Injiziert den Spieler-Kontext als JavaScript-Objekt
- Lädt die HTML-Datei des Moduls (Template-Replacement oder direktes PHP)
Spieler-Kontext (PHP → JS)
<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 (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.
{
"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
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
*_easyfürmodule_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)
--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 rechtsshowEvent(icon, text, type)— Notification im Canvas + Stapel (type: 'good'/'bad'/'neutral')toggleEventStack()— Event-Stapel auf/zuklappenupdateGraph(index, points, currentValue)— Klick auf Graph vergrössertupdateParam(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— Benutzerverwaltungstudent_sessions— Anonyme Sessionsgame_levels— Level-Konfiguration pro Modul × Schwierigkeitplayer_progress— XP, Level-Stand, Badgesassessment_answers— Reflexionsantwortenclass_modules— Modul-Freigabe pro Klasselicenses— 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_waypointsfü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:
- 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
- Schlüssel-Format:
- Server-Backup (Sekundär, bei vorhandener Session): Zusätzlich per POST an
/api/saves.phpschicken, damit der Fortschritt auf anderen Geräten verfügbar ist. Fällt das Netz aus, ist localStorage der Fallback.
Konkrete Implementierung
// 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
beforeunloadals 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-layoutZonen - Action-Cards nutzen
ggs-cardKlasse - Parameter nutzen
ggs-parammit 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)