- 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>
20 KiB
GeoGraSim — Sim-Spec für externe KI-Entwicklung
Stand: 2026-06-12 · Ergänzung zu module-interface.md und integration-konzept.md.
Wichtig: Dieses Dokument fasst nur das Neue / Geänderte seit Juni 2026 zusammen und bündelt die für eine externe KI essentiellen Schnittstellen. Die historischen Files bleiben gültig für: Sprache (Lernarbeit statt Spiel · Leichte Sprache), iPad-Pattern, Persistenz/Resume, Datei-Struktur, Datenmodell-Grundlagen.
0. TL;DR — Was eine neue Sim aus Plattform-Sicht ist
App/sims/<sim-id>/game.html ← deine HTML-Datei
App/sims/<sim-id>/engine.js ← optional, separate JS-Logik
App/sims/<sim-id>/assets/ ← optional, sim-eigene Bilder/Sounds
App/pages/<sim-id>.php ← PHP-Wrapper (Plattform-Standard, Atlas legt an)
Plus 1 Eintrag in der DB-Tabelle module_info (Title, Icon, Status, sort_order — Atlas macht das).
Die Sim selbst ist ein selbst-laufender Browser-Frontend-Block. Sie spricht mit der Plattform NUR über die 4 Window-Globals (siehe §2) und einen einzigen HTTP-Endpoint /api/progress.php zum Speichern (siehe §3).
1. Plattform-Conventions (Stand Juni 2026)
Drei Window-Globals + ein optionales Lib. Vollständige Doku im Header von /assets/js/live-client.js.
1.1 window.__GGS__ — Plattform setzt, Sim liest
Wird vom PHP-Wrapper VOR der Sim-Logik gesetzt:
window.__GGS__ = {
sessionId: 'uuid', // anonyme Session
studentId: 12, // optional, null bei Gast
classId: 3, // optional
simId: 'kofferdetektiv',
simName: 'Kofferdetektiv',
level: 1,
baseUrl: '/geograsim/App', // oder '' auf Prod
apiUrl: '/geograsim/App/php/api',
basePath: '/geograsim/App',
mode: 'free', // 'free' | 'teacher_started' | 'locked'
forcedLevel: null, // wenn 'teacher_started': Pflicht-Level
easy: false, // Leichte Sprache aktiv?
};
Wenn __GGS__ nicht da ist, läuft die Sim trotzdem (Dev/Direkt-URL) — sie sollte robust mit undefined umgehen.
1.2 window.GGS_LIVE_STATE — Sim setzt eine Funktion
Funktion, die einen Snapshot des aktuellen Sim-Zustands zurückgibt. Wird vom Plattform-Live-Client alle 4 s aufgerufen und ans Lehrer-Cockpit gestreamt.
window.GGS_LIVE_STATE = function () {
if (!gameReady) return null;
return {
simId: 'kofferdetektiv',
phase: 'fall-3-zoll', // freier Text — was passiert gerade
progressPct: 60, // 0-100, didaktische Empfehlung
score: 42, // wenn schon scorebar
health: 'good', // good | ok | struggle (für Status-Punkt)
// weitere sim-spezifische Felder — Cockpit picked sich, was es kann
};
};
Fallstrick (echter Bug von Fluss am 2026-06-11): Nutze KEINE Property params auf einem Objekt, wenn params nicht direkt darauf existiert. if (!game.params) true → Snapshot null → Cockpit zeigt „meldet keine Live-Werte" obwohl die Sim läuft. Lies State direkt aus dem Computed-Result.
1.3 window.GGS_TUTORIAL — Sim registriert Replay-Hook
Damit der ℹ-Button im Header das Onboarding nochmal öffnet:
window.GGS_TUTORIAL = {
simId: 'kofferdetektiv',
title: '🕵️ Kofferdetektiv',
replay: function () { startTutorial(); }, // deine eigene Funktion
};
Der Button wird in der Sim selbst eingefügt (siehe §4.2 Header-Standard).
1.4 window.__GGS_LIVE__ — Plattform setzt, Sim liest
Read-only Proxy, von live-client.js bereitgestellt:
window.__GGS_LIVE__ = {
activeMs: number, // aktive Spielzeit (gecappt bei 7_200_000 = 120 min)
idleMs: number, // Zeit seit letzter Interaktion
sessionStartedAt: timestamp,
lastInteractionAt: timestamp,
capped: boolean,
MAX_SESSION_MS: 7200000,
IDLE_THRESHOLD_MS: 90000,
};
Wann lesen: Beim Submit als duration_ms — bitte __GGS_LIVE__.activeMs statt Date.now() - start benutzen. Sonst landet auch Idle-Zeit (Tab vergessen) in der DB. Plattform-Cap zusätzlich im Backend defensiv.
1.5 Reservierte __-Heartbeat-Keys
Der Live-Client mischt automatisch in jeden GGS_LIVE_STATE-Snapshot:
state.__activeMs, state.__idleMs, state.__lastInteractionAt,
state.__sessionStartedAt, state.__capped
Niemals überschreiben — Cockpit liest diese aus.
2. Plattform-Bibliotheken (optional einbindbar)
2.1 Glossar-Tooltip
<script src="/assets/js/glossar-tooltip.js" defer></script>
<script>
window.addEventListener('DOMContentLoaded', () => {
GlossarTooltip.init({
apiBase: '/php/api',
moduleId: 'kofferdetektiv', // filtert DB auf sim-eigene Begriffe
});
});
</script>
Im Markup:
<span class="ggs-g" data-glossar="zollkontrolle">Zollkontrolle</span>
Wirkung: Tap/Klick → Popup mit Kurztext + Link zum vollen Glossar-Eintrag. Tooltip-CSS wird automatisch injiziert. Hat zentralen Style — nicht selbst CSS für .ggs-g schreiben.
Vorgehen für neue Glossar-Begriffe: in der DB-Tabelle glossar anlegen, module_id setzen. Atlas oder Glossar-Instanz macht das.
2.2 Quick-Intro (Mini-Onboarding-Modal)
Für Sims OHNE volles Tutorial. Bietet ein einheitliches Modal beim 1. Besuch + Replay-Funktion.
<script src="/assets/js/ggs-quick-intro.js" defer></script>
<script>
window.addEventListener('DOMContentLoaded', () => {
GgsQuickIntro.init({
simId: 'kofferdetektiv',
title: '🕵️ Kofferdetektiv',
lead: 'Du untersuchst beschlagnahmte Koffer am Flughafen. Was darf rein, was nicht — und warum?',
steps: [
'Koffer öffnen — du siehst Inhalt + Herkunft + Zielland.',
'Gegenstände prüfen — viele Vorschriften erschließen sich aus Geografie + Politik.',
'Entscheidung treffen: durchlassen, beanstanden oder beschlagnahmen.',
'Feedback bekommen — pro Entscheidung Lehrtext + Glossar.',
],
goals: [
'Zoll- und Einreisebestimmungen verstehen',
'Herkunftsländer von Produkten geografisch einordnen',
'Gesetzeskunde im Kontext (Artenschutz, Drogen, Lebensmittel)',
],
});
});
</script>
Verhalten: 1. Besuch → Modal auto-open. localStorage merkt sich „gesehen" (ggs.intro.<simId>). Library registriert automatisch window.GGS_TUTORIAL.replay(). ℹ-Header-Button öffnet das Modal wieder.
Du kannst alternativ ein volles, sim-spezifisches Tutorial bauen (mehrere Schritte mit Bildern + Glossar-Begriffen — siehe weltkueche/game.html als Referenz). Dann musst du nur window.GGS_TUTORIAL = {simId, title, replay: deineFunktion} selbst setzen.
2.3 Live-Client (live-client.js)
Wird vom PHP-Wrapper automatisch eingebunden — Sim muss nichts tun. Library trackt Idle (siehe §1.4), sendet Heartbeats an /api/live.php, pollt Pause-Flag.
3. Submit-Pfad — Wie die Sim ihre Daten persistiert
Drei Aktionen via POST /api/progress.php mit JSON-Body. Auth läuft automatisch über die Session-Cookie aus __GGS__.
3.1 Live-Fortschritt (optional, alle paar Aktionen)
fetch(__GGS__.apiUrl + '/progress.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'same-origin',
body: JSON.stringify({
sim_id: 'kofferdetektiv',
action: 'update',
data: { phase: 'fall-3', score: 42 },
}),
});
Selten nötig — GGS_LIVE_STATE deckt das eigentlich ab. Nur wenn du persistente Zwischenstände in der DB willst.
3.2 Reflexionsantwort (zwischen Phasen)
fetch(__GGS__.apiUrl + '/progress.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'same-origin',
body: JSON.stringify({
sim_id: 'kofferdetektiv',
action: 'reflection',
data: {
level: 1,
question: 'Was war dein schwierigster Fall?',
answer: 'Der Koffer aus Kenia',
},
}),
});
3.3 Abschluss-Submit (Pflicht — am Ende einer Stufe)
fetch(__GGS__.apiUrl + '/progress.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'same-origin',
body: JSON.stringify({
sim_id: 'kofferdetektiv',
action: 'submit_assessment',
data: {
level: 1,
stars: 3,
score: 72,
duration_ms: (window.__GGS_LIVE__ && window.__GGS_LIVE__.activeMs) || 0,
completed: true,
results: {
// SIM-SPEZIFISCHE Felder. Die Plattform-Benchmark-Engine
// erwartet von dir konkrete Keys (siehe §5) — bitte mit Atlas
// abstimmen, bevor du das Schema festschreibst.
cases_solved: 8,
cases_total: 10,
correct_first_try: 6,
wrong_decisions: 1,
glossar_consulted: 4,
},
},
}),
});
Wichtig: results ist sim-spezifisches JSON. Es wird in assessments.results als String gespeichert und sowohl im Lehrer-Cockpit (live.php) als auch im Ergebnisse-Tab (results.php) ausgelesen. Konventionen pro Sim folgen aus der Benchmark-Formel — siehe §5.
4. Design-System (Pflicht)
CSS-Variablen + Layout-Klassen aus /assets/css/design-system.css.
4.1 Farb-Variablen
--ggs-fjord /* Primärblau, Headlines */
--ggs-fjord-dark /* Dunkler Akzent */
--ggs-moss /* Erfolg/Grün */
--ggs-sand /* Kosten/Neutral */
--ggs-coral /* Gefahr/Rot */
--ggs-orange /* Warnung */
UI-Farben sind NICHT die Bild-Palette (siehe §6).
4.2 Header-Standard (Plattform-konform)
<header class="ggs-header">
<a href="/schueler" class="ggs-header-logo">
<img src="/assets/img/bildLogo.png" alt="" class="ggs-header-logo-icon">
<img src="/assets/img/textlogo_geograsim.svg" alt="GeoGraSim" class="ggs-header-logo-text">
</a>
<div class="ggs-header-separator"></div>
<span class="ggs-header-module">Kofferdetektiv</span>
<span class="ggs-header-badge">Stufe 1</span>
<div class="ggs-header-spacer"></div>
<div class="ggs-header-actions">
<!-- Plattform-Standard: ℹ als ERSTER Button vor 📚 -->
<button class="ggs-btn-ghost" id="btn-info"
title="Anleitung nochmal zeigen"
onclick="if(window.GGS_TUTORIAL&&typeof window.GGS_TUTORIAL.replay==='function')window.GGS_TUTORIAL.replay();">ℹ</button>
<a class="ggs-btn-ghost" id="ggs-lehrplan-link" href="#" target="_blank" title="Lehrplan-Bezug">📚</a>
<button class="ggs-btn-ghost" id="btn-mute" title="Ton aus/an">🔊</button>
<button class="ggs-btn-ghost" id="btn-reset" title="Fortschritt zurücksetzen">🔄</button>
<a href="/schueler" class="ggs-btn-ghost" title="Zurück zum Cockpit">🏠</a>
</div>
</header>
Regel: ℹ = Tutorial-Replay (Plattform-Convention). Wenn deine Sim einen anderen Info-Inhalt hat (z.B. Fachinfo/Glossar in Farmer), kommt der mit eigenem Icon — 📖 für Glossar, 📚 für Lehrplan.
4.3 Layout-Zonen
ggs-sim-layout 3-Spalten-Grid (Status links, Sim Mitte, Aktionen rechts). Details in module-interface.md §5.
4.4 Cockpit-Sichtbarkeit (LIVE_PRIMARY_FIELDS)
Damit deine Sim im Lehrer-Cockpit sinnvolle Spalten zeigt, muss Atlas in teacher.html einen LIVE_PRIMARY_FIELDS['kofferdetektiv']-Eintrag setzen. Beispiel:
'kofferdetektiv': [
{k:'health', label:'Status', align:'center', fmt: v => LIVE_VALUE_LABELS.health[v] || '—'},
{k:'phase', label:'Phase'},
{k:'progressPct', label:'Fortschritt', fmt: v => _liveBar(v, 0, 100, 'mid')},
{k:'score', label:'🏅 Score', fmt: v => _liveBar(v, 0, 100, 'high')},
{k:'cases_solved', label:'Gelöst'},
{k:'correct_first_try',label:'1.-Versuch ✓'},
],
Range-Bars: Helfer _liveBar(val, min, max, goodWhen). goodWhen: 'high' (grün ab 60% Range), 'low' (invers — niedrig=gut), 'mid' (neutral grau).
Vorgehen für externe KI: Liefere Atlas einfach die Liste deiner GGS_LIVE_STATE-Felder + welche davon Range-Bars wert sind. Atlas patcht teacher.html.
5. Benchmark-Engine — Sim braucht eine Scoring-Formel
Die Plattform berechnet pro Submission einen 0–100-Modul-Score (für Lehrer-Cockpit Top 3 / Bottom 3 und Ergebnisse-Tab). Die Formel lebt in App/php/lib/Benchmark.php als private statische Methode.
Pro neuer Sim: du lieferst die Formel-Idee, Atlas integriert sie. Beispiel-Briefing (Kofferdetektiv):
scoreKofferdetektiv($results) {
$solved = $results['cases_solved'] ?? 0;
$total = $results['cases_total'] ?? 0;
$firstTry = $results['correct_first_try'] ?? 0;
$wrong = $results['wrong_decisions'] ?? 0;
if ($total === 0) return null;
$base = ($solved / $total) * 70; // 70 % Lösung
$bonus = ($firstTry / $total) * 30; // 30 % Sauberkeit
$malus = min(20, $wrong * 5); // bis -20 für Fehlentscheidung
return max(0, min(100, $base + $bonus - $malus));
}
Wichtig:
- Wenn keine bewertbaren Daten →
null(lieber „noch keine Bewertung" als geratene Zahl). - Pro Modul max. die 3 besten Sessions zählen — macht die Engine selbst.
6. Bildstil — Flat Scandinavian
Für ALLE Bilder in der Sim (Onboarding, Kategorie-Icons, Karten-Backgrounds, Charakter-Avatare):
Palette:
Background #e8e4d8 (warmer Sand)
Primär #1f4b37 (Forest)
Sekundär #4a7c4e (Moss)
Akzent #e8c547 (Honey)
Detail #b04a3e (Coral, sparsam)
DALL-E-Prompt-Block (Standard):
Flat scandinavian illustration, geometric shapes, soft warm color palette
(#1f4b37 forest, #4a7c4e moss, #e8c547 honey, #e8e4d8 sand background,
#b04a3e coral accent sparingly). No people unless explicit, no text, no
photo-realism. Clean educational style for children 10-14, Sek I.
[hier deine Sim-Szene]. Square 1024x1024.
Auflösungen:
- Onboarding-Karten: 1024×1024 → WebP, max 200 KB
- Sim-eigene Bilder: 512×512 oder 1024×1024 je nach Verwendung
- Glossar-Illustrationen: 512×512 (Atlas verwaltet das zentral)
Standorte: App/sims/<sim-id>/assets/img/ für sim-eigene; App/assets/img/glossar/ für Glossar.
7. Sprache (Pflicht — schon in module-interface.md §4a)
Kurz zur Erinnerung:
| Nicht | Sondern |
|---|---|
| spielen, Spiel | arbeiten mit, Simulation, bearbeiten |
| Spieler:in | Lernende, Bearbeiter:in |
| Game Over | Ziel verfehlt / Durchgang beendet |
| Highscore | Beste Leistung |
| Lehrkraft | Lehrperson (österreichisches Pädagog:innen-Bildungsgesetz) |
Begründung: Wygotski-basierte Lernarbeit-Sprache. Wenn die Sim für Schüler:innen sichtbar wird, gilt das strikt.
Plus: Sek-I-Tonalität (10–14 Jahre). Nicht infantil, nicht erwachsen. Du-Form, aber höflich.
8. Persistenz, iPad-Pattern, Leichte Sprache
Alle drei sind in module-interface.md abgehandelt und gelten weiter:
- Persistenz (§7b): localStorage Autosave + Server-Mirror, Reload führt nie zum Neustart, expliziter Reset-Button mit Bestätigung.
- iPad (§4c): 1180×820 Referenz, Touch-Ziele 36–40 px, kein Hover-Kleber,
font-size: 16pxfür Inputs. - Leichte Sprache (§4b): Plattform-DB liefert Easy-Varianten von Glossar/Lehrplan automatisch, wenn Lehrperson das pro Schüler:in setzt.
9. Workflow für eine neue Sim (Pragmatisch)
- Konzept-Skizze an Atlas: Was lernen sie? Wie ist die Mechanik? Welche Stufen? Welche Lehrplan-Anbindung?
- Atlas legt an:
module_info-Eintrag (Title, Icon, Status='entwurf', sort_order)App/pages/<sim-id>.php-Wrapper- Routing in
.htaccess - Glossar-Begriffe einsammeln (an Glossar-Instanz weitergeben)
- Externe KI baut
App/sims/<sim-id>/:game.htmlmit Plattform-Header + GGS_LIVE_STATE + GGS_TUTORIAL/QuickIntro- Engine in JS (vanilla, kein Build-Step)
- Submit-Pfad bei Phasen-Ende
- localStorage-Autosave
- Atlas integriert:
LIVE_PRIMARY_FIELDS['<sim-id>']in teacher.htmlBenchmark::score<SimName>()in Benchmark.php- Playwright-Tests in
.dontDeploy/playwright/tests/stufe1-smoke/ - Deploy + Test
- Status auf
aktivschalten (über admin-modules.html oder direktes SQL).
10. Test-Pattern (Stufe 1 Smoke)
Pro Sim mindestens 1 Test in .dontDeploy/playwright/tests/stufe1-smoke/:
test('Sim kofferdetektiv · __GGS__ + live-client + GGS_LIVE_STATE', async ({ page }) => {
await page.goto('https://geograsim.at/kofferdetektiv');
await page.waitForTimeout(2500);
const info = await page.evaluate(() => ({
ggs: typeof window.__GGS__,
state: typeof window.GGS_LIVE_STATE,
tutorial: typeof window.GGS_TUTORIAL,
}));
expect(info.ggs).toBe('object');
expect(info.state).toBe('function');
expect(info.tutorial).toBe('object');
});
Existing Pattern in sim-platform-context.spec.js deckt alle Sims ab — Atlas ergänzt deinen Sim-Slug dort.
11. Referenz-Sims als Vorbild
Wenn die externe KI ein gutes Vorbild für die Code-Struktur braucht:
App/sims/weltkueche/game.html— full Tutorial-Pattern + Glossar-Tooltip in Tutorial-Texten + saubere Submit-Logik. Mittelgroß (~2000 LoC).App/sims/busfahrt/game.html— Karten-basierte Sim mit Quick-Intro statt full Tutorial. Topbar mit eigenem Styling.App/sims/eu-werkstatt/game.html— Drag-and-Drop / Card-Sorting-Pattern.App/sims/sonnensystem/game.html— 3D-Canvas (Three.js) + state-driven Aufgaben.
Die externe KI sollte mindestens eine dieser Sims lesen, bevor sie ihre eigene baut — um Plattform-Header, Glossar-Anbindung und Submit-Pattern abzukucken.
12. Was die externe KI explizit NICHT machen soll
- Keine eigenen URL-Routen / .htaccess-Eingriffe — Atlas macht das.
- Keine Schema-Änderungen an DB-Tabellen ohne Rückfrage.
- Keine API-Calls in Endpoints, die nicht in §3 stehen.
- Keine eigenen Plattform-Bibliotheken in
/assets/js/ergänzen — wenn dir was zentral fehlt, melde es Atlas. - Keine Spiel-Sprache. Ernsthaft — siehe §7.
- Keine echten KI-Calls IM Produkt (OpenAI/Claude/Anthropic-API). Auswertung ist parametrisch. (Tutorial-Inhalte mit KI vorgenerieren ist OK, im Produkt landet das als statischer Content.)
13. Erstkontakt-Briefing für die externe KI (Copy-Paste)
Du baust ein neues GeoGraSim-Sim-Modul namens "<sim-id>".
Plattform-Kontext + Conventions: docs/sim-spec-2026-06-12.md (dieses Doc) +
docs/module-interface.md.
Hard Constraints:
- Vanilla HTML/JS/CSS. Kein Build-Step. Kein React/TypeScript.
- Plattform-Header genau wie in §4.2.
- window.GGS_LIVE_STATE() liefern (§1.2).
- window.GGS_TUTORIAL setzen oder ggs-quick-intro.js nutzen (§1.3 / §2.2).
- Submit am Ende via POST /api/progress.php (§3.3).
- duration_ms aus __GGS_LIVE__.activeMs lesen (§1.4).
- Sprache: Lernarbeit, nicht Spiel (§7).
- iPad-tauglich (siehe module-interface.md §4c).
- Persistenz: Reload darf nie neu starten (siehe module-interface.md §7b).
Liefere am Ende:
- App/sims/<sim-id>/game.html (+ engine.js wenn separat)
- Liste deiner GGS_LIVE_STATE-Felder + welche Range-Bars Sinn machen
- Vorschlag für Scoring-Formel (Benchmark §5)
- Glossar-Begriffe, die du im Tutorial verwendest
Atlas integriert dann teacher.html, Benchmark.php, .htaccess, DB.
14. Ansprechpartner & Files-Map
| Fragen zu | Wer / Wo |
|---|---|
| Plattform-API / live-client / Cockpit | Atlas, /assets/js/live-client.js, /teacher.html, /php/api/live.php |
| Submit-Endpoint, assessments-Schema | Atlas, /php/api/progress.php, /php/api/assessment.php |
| Benchmark-Formel pro Sim | Atlas, /php/lib/Benchmark.php |
| Glossar-Begriffe / Tooltip-Pattern | Glossar-Instanz / Atlas, DB-Tabelle glossar + /assets/js/glossar-tooltip.js |
| Lehrplan-Anbindung / Kompetenz-Mapping | Lehrplan-Instanz / Atlas, DB-Tabellen kompetenzen/kompetenz_modules/lehrplan_anchors |
| Design-System-Klassen | /assets/css/design-system.css |
| Bildstil + DALL-E-Prompts | Atlas, §6 hier + Memory reference_bildstil |
Fragen? An Atlas (Plattform-Instanz). Diese Spec wird laufend gepflegt — bei jeder neuen Convention bitte hier ein Update einreichen statt Side-Doc.