Files
geograsim/App/docs/module-interface.md
T
Adminator 9a61f55cb1 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>
2026-04-19 11:51:14 +02:00

22 KiB
Raw Blame History

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)

<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.

{
  "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 *_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


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)

--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

// 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)