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
+643
View File
@@ -0,0 +1,643 @@
# GeoGraSim — Architektur & Schnittstellen
> **Zweck dieses Dokuments**
> Zentrale Referenz für alle Module, Datentypen, Schnittstellen und Konventionen.
> Geschrieben so, dass sowohl ein Mensch als auch eine KI das gesamte Projekt verstehen
> kann, ohne den Source-Code zu lesen. Bei jeder größeren Änderung dieses Dokument
> aktualisieren.
>
> **Stand:** April 2026 (nach Strom-System, 3 Schwierigkeitsgraden, Bilanz-UI, Steg-Rampe, Graph-Zoom, Auto-Pause)
---
## 1. Verzeichnis-Struktur
```
App/
├── index.html # Übersicht aller Simulationen
├── game-3d.html # Klimawächter 3D-Renderer (Hauptspiel)
├── game.html # Klimawächter 2D-Renderer (älter, hinkt hinterher)
├── erdbeben.html # SIM-07: Erdbeben
├── energiemix.html # SIM-09: Energiemix
├── stilauswahl.html # Frontend-Stil-Auswahl-Tool
├── src/
│ ├── core/
│ │ └── game-engine.ts # Basis-Klasse aller Simulationen
│ ├── ui/
│ │ ├── game-ui.ts # Generic GameUI (Resources, Goals, Shop, Graphs, ...)
│ │ ├── info-overlay.ts # Tooltips + erklärende Overlay-Modals
│ │ └── theme.ts # (falls vorhanden) Farb-Themes
│ └── sims/
│ ├── sim-05-treibhaus/ # Klimawächter Logik (engine-level)
│ │ ├── game.ts # KlimawaechterGame, MEASURES, DIFFICULTY_LEVELS
│ │ └── logic.ts # computeTemperature() etc.
│ ├── sim-05-treibhaus-3d/ # 3D-Renderer für Klimawächter
│ │ └── game-renderer-3d.ts (~1900 Zeilen)
│ ├── sim-07-erdbeben/ # SIM-07
│ └── sim-09-energiemix/ # SIM-09
├── tests/unit/
│ ├── sim-05-trace.test.ts # Mechanik-Trace über 75 Jahre, 7 Strategien
│ ├── sim-05-treibhaus.test.ts # Standard-Tests
│ └── ... (pro Sim)
└── docs/
├── architektur.md # ← DIESES DOKUMENT
├── klimawaechter-dev-log.html # Entwicklungs-Log
└── ...
```
---
## 2. Core-Schicht: `game-engine.ts`
Die `GameEngine`-Basisklasse stellt alle gemeinsamen Mechaniken bereit:
Ressourcen, Ziele, Tutorial, Events, Tick-Loop, Save/Load, Citizen-Events, State-Machine.
### 2.1 Lifecycle
```
constructor(meta) → setupResources() → setupGoals() → setupTutorial()
state: 'tutorial' (warten auf Spieler-Klick durch Tutorial-Schritte)
state: 'running' (msPerTick × speed → simulateTick() pro Zeitschritt)
state: 'won' | 'lost' (checkWinCondition / checkLossCondition)
```
### 2.2 GameMeta
```typescript
interface GameMeta {
id: string // 'sim-05'
title: string // 'Klimawächter'
description: string
msPerTick: number // Wieviele ms pro Tick (4000 = 4 Sek/Jahr)
tickUnit: string // 'Jahr', 'Monat', etc. (UI-Beschriftung)
maxTicks: number // Spielende-Tick (75 für 2025-2100)
tutorialSteps: number // Anzahl der Schritte (siehe setTutorial)
}
```
### 2.3 Resources
```typescript
interface Resource {
id: string // eindeutig: 'budget', 'population', ...
name: string // Anzeige
icon: string // Emoji
initial: number
unit: string // 'Mio €', 'MW', 'cm', ...
format?: (v: number) => string // Custom Display-Format
current: number // wird vom Engine gehalten
}
// API:
addResource(r: Resource) // im constructor() aufrufen
setResource(id, value)
getResource(id): number
changeResource(id, delta)
getResourcesArray(): Resource[]
```
**Konvention:** Custom `format`-Funktionen können auf andere Ressourcen zugreifen:
```typescript
this.addResource({
id: 'power', initial: 0,
format: (v) => {
const demand = Math.round(this.getResource('population') / 1000)
return `${demand}/${Math.round(v)} MW`
}
})
```
### 2.4 Variables (interne, nicht angezeigte Werte)
```typescript
setVariable(key, value)
getVariable(key): number
```
Werden für interne Berechnungen verwendet, erscheinen nicht in der UI. Beispiele:
`co2Reduction`, `protection`, `upkeepTotal`.
### 2.5 Goals
```typescript
interface Goal {
id: string
title: string
description: string
check: (game: GameEngine) => boolean // erreicht?
progress?: (game: GameEngine) => number // 0-100 für Progress-Bar
required: boolean // muss für 'won' erfüllt sein
}
addGoal(g: Goal)
```
### 2.6 Events (Ereignis-Karten in der UI)
```typescript
addEvent(id, text, severity, infoKey?)
// severity: 'info' | 'success' | 'warning' | 'danger'
// infoKey: optional Schlüssel für INFO_TOPICS Lookup
getEvents(limit): Event[]
```
`id` macht es idempotent (jedes Event nur einmal). Mit `eventFired(id)` aus
einer Subklasse kann man prüfen, ob ein Event schon ausgelöst wurde.
### 2.7 Citizen Events (modale Bürger-Dilemmata)
```typescript
interface CitizenEvent {
id: string
character: string // Emoji-Avatar
title: string // 'Lina, die Fischerin'
message: string // 1-3 Sätze, kindgerecht
choices: CitizenChoice[]
}
interface CitizenChoice {
label: string // Button-Text
description: string // Vor-/Nachteile-Hint
apply: (game: GameEngine) => void
}
triggerCitizenEvent(ev: CitizenEvent)
getPendingCitizenEvent(): CitizenEvent | null
resolveCitizenEvent(choiceIdx: number)
```
Die UI zeigt das Modal automatisch an, wenn `pendingCitizenEvent !== null`.
**Nur eines gleichzeitig.**
### 2.8 Tick-Loop
```typescript
protected simulateTick(): void // ← in Subklasse implementieren
setSpeed(s: 0 | 1 | 2 | 4) // 0 = Pause
getSnapshot(): { tick, speed, state, goals[], timeline[] }
```
Die Engine ruft `simulateTick()` periodisch auf. `tick` zählt bei jedem Aufruf
hoch. Bei jedem Tick wird `notify()` gerufen → UI rendert neu.
### 2.9 Save / Load
```typescript
serialize(): string // JSON
deserialize(s: string): boolean // gibt false bei alter Version
// Subklassen-Hooks (überschreibbar):
protected serializeSubclass(): Record<string, unknown>
protected deserializeSubclass(data: Record<string, unknown>): void
```
**Versionierung:** `SAVE_VERSION = 2`. Saves mit anderer Version werden
abgelehnt → neues Spiel. Bei Mechanik-Änderungen Version erhöhen.
**Save-Format (Auszug):**
```json
{
"version": 2,
"tick": 12,
"state": "running",
"speed": 1,
"resources": { "budget": 437, ... },
"variables": { "co2Reduction": 1.2, ... },
"goalsAchieved": ["temp"],
"events": [...],
"subclass": { /* serializeSubclass() output */ }
}
```
---
## 3. UI-Schicht: `game-ui.ts`
Generische UI-Klasse, die von jeder Sim-HTML-Seite verwendet wird. Erwartet
DOM-Elemente mit bestimmten IDs (siehe unten) und rendert da hinein.
### 3.1 GameUIConfig
```typescript
interface GameUIConfig {
game: GameEngine
Renderer: new (container: HTMLElement, game: any) => Renderer
shopItems: ShopItem[]
onBuy: (id: string) => boolean
onDemolish?: (id: string) => boolean // Optional: 🗑-Button
getOwnedCount?: (id: string) => number // Optional: ×N Badge
graphs: GraphConfig[]
saveKey: string // localStorage key
finishOnTick?: number
yearOffset?: number // 2025
mode?: 'free' | 'guided'
totalDurationSec?: number // bei mode=guided
statusResources?: string[] // Whitelist welche Resources im Status-Panel
}
```
### 3.2 ShopItem
```typescript
interface ShopItem {
id: string
name: string
emoji: string
description: string
cost: number
upkeep: number
badges?: { label: string; type: BadgeType }[]
}
type BadgeType = 'cost' | 'reduction' | 'protection' | 'capacity' | 'quality' | 'neutral'
```
### 3.3 GraphConfig
```typescript
interface GraphConfig {
id: string // SVG-Element-ID
title: string
field: string // Resource-ID, dessen Werte geplottet werden
yMin: number
yMax: number
color: string // CSS-Farbe
unit?: string
zones?: GraphZone[] // farbige Bänder im Hintergrund
lines?: GraphLine[] // horizontale Referenzlinien
autoScale?: boolean // yMax wandert mit Daten mit
}
```
### 3.4 Erwartete DOM-Element-IDs (HTML-Seite)
| ID | Inhalt |
|---|---|
| `#canvas-wrap` | Container für 3D/2D Renderer |
| `#resources` | Status-Box (Resources werden hier eingefügt) |
| `#status-goals` ODER `#goals` | Ziele-Liste |
| `#measures` | Shop |
| `#events` | Vollständige Ereignis-Liste (Popout) |
| `#events-latest` | Nur das letzte Event (Trigger in Status-Box) |
| `#tutorial`, `#tut-title`, `#tut-text`, `#tut-dots`, `#tut-next` | Tutorial-Modal |
| `#end-screen-host`, `#citizen-event-host`, `#info-overlay-host` | Modal-Slots |
| `[data-speed="0|1|2|4"]` | Speed-Buttons |
| `#btn-save`, `#btn-load`, `#btn-finish`, `#btn-reset` | System-Buttons |
### 3.5 Sim-Spezifische UI-Sonderfälle (Duck-Typing)
`GameUI` ist generisch, hat aber **drei Hooks** für sim-spezifische UI-Erweiterungen:
1. **`power`-Resource** → `updatePowerGrid()` rendert Bedarf/Kapazitäts-Balken
2. **`budget`-Resource + `game.getYearlyBalance()`** → `updateBudgetBalance()` rendert Bilanz-Tabelle
3. **Resource-Format-Closures** dürfen `this` (das Game-Objekt) nutzen
**Konvention:** Sim-spezifische UI-Logik in `game-ui.ts` mit Kommentar
`// Spezialfall <NAME>:` markieren.
### 3.6 Public API (von außen aufrufbar)
```typescript
ui.getRenderer(): Renderer | null // für Kamera-Steuerung
ui.redrawGraphs(): void // erzwingt Graph-Neuzeichnung (nach Resize)
```
---
## 4. Renderer-Schicht: `game-renderer-3d.ts`
Three.js-basierter 3D-Renderer. Konstruktor erhält `(container, game)` und
hängt sich selbst an `container`.
### 4.1 Erwartete Methoden eines Renderers
```typescript
interface Renderer {
start(): void
stop(): void
// optional, für UI-Buttons:
zoomIn?(): void
zoomOut?(): void
recenter?(): void
}
```
### 4.2 KlimawaechterRenderer3D — interne Struktur
```
Scene
├── Wasserfläche (steigt mit sealevel)
├── Himmel-Kuppel
├── Insel (PlaneGeometry mit Vertex-Colors, 120×160 Segmente)
├── Vulkan-Kuppel + Schnee-Gletscher (LatheGeometry, ClippingPlane)
├── Steg + Rampe + wartende Bewohner-Sprites
├── villageGroup (Häuser + 3 Baumtypen mit Stadien)
├── smokeGroup (Heizwolken pro Haus)
├── fxGroup (FX-Effekte: Totenkopf, Boot, Skulls)
├── placed[] (gekaufte Maßnahmen)
└── mountainShieldGroup? (wenn hasMountainShield)
```
### 4.3 Wichtige Konstanten
```typescript
ISLAND_HALF_WIDTH = 13 // X-Halbachse
ISLAND_HALF_LENGTH = 17 // Z-Halbachse
WATER_Y_BASE = 0.0 // Start-Wasserlinie
MAX_SEA_RISE_UNITS = 1.6 // Wasser steigt bis +1.6 Y bei 200 cm Sealevel
VOLCANO_X = -3.0
VOLCANO_Z = -11.0
VOLCANO_DOME_HEIGHT = 2.1
VOLCANO_DOME_RADIUS = 2.2
ZONE_BEACH_END = 0.38 // Vertex-Color-Zonen
ZONE_MEADOW_END = 0.95
ZONE_FOREST_END = 1.80
```
### 4.4 FX-System
```typescript
interface FxEffect {
root: THREE.Object3D
lifetime: number
age: number
update: (dt: number, ef: FxEffect) => boolean // false → entfernen
}
private fxEffects: FxEffect[] = []
private fxGroup: THREE.Group
// Pro Frame in updateScene():
for (let i = fxEffects.length - 1; i >= 0; i--) {
if (!fxEffects[i].update(dt, fxEffects[i])) fxEffects.splice(i, 1)
}
```
Spawn-Helpers:
- `spawnSkull(x, y, z)` — 💀 schwebt 1.2 Units nach oben, 3.2s Lebensdauer
- `spawnRefugeeBoat()` — Boot mit Boarding → Spirale → Escape (28s total)
- `makeEmojiSprite(emoji, size)` — Billboard-Sprite mit CanvasTexture
### 4.5 Maßnahmen-Platzierung
```typescript
private placeMeasure(typeId: string, index: number): THREE.Object3D | null
```
Switch über `typeId`. Pro neuem Measure-Typ ein neuer Case + ein
`makeXxx()`-Helper. Das Renderer-Update-Loop scannt `game.getOwnedMeasures()`
und ruft `placeMeasure` für neue, entfernt Meshes für demolierte.
---
## 5. Sim-Spezifisch: `sim-05-treibhaus/game.ts`
### 5.1 KlimawaechterGame
Erbt von `GameEngine`. Ungefährer Aufbau:
```typescript
export class KlimawaechterGame extends GameEngine {
private measures: OwnedMeasure[]
private diff: DifficultyConfig
private co2Ppm = 425
private currentTemp = 0
private targetTemp = 0
private seaLevelCm = 0
private floodedHouses = 0
researchDiscount = 1.0
tourismMode = false
hasMountainShield = false
treesChoppedForHeat = 0
private blackoutStreak = 0
private firedEvents = new Set<string>()
constructor(difficulty: 1|2|3 = 2)
// Public API
buyMeasure(id): boolean
demolishMeasure(id): boolean
getOwnedMeasures(): OwnedMeasure[]
getMeasureCount(id): number
getDifficulty(): DifficultyConfig
getYearlyBalance(): { income, tourism, upkeep, climate, net }
getIncomeAtCurrentLevel(): number
// Subclass-Hooks
protected simulateTick()
protected serializeSubclass()
protected deserializeSubclass()
protected checkLossCondition()
}
```
### 5.2 MEASURES-Tabelle (Stand April 2026)
| id | name | cost | upkeep | co2Reduction | protection | powerOutput |
|---|---|---|---|---|---|---|
| `forest` | 🌲 Wald | 12 | 0.5 | -0.04 | | |
| `solar` | ☀️ Solar | 40 | 2 | -0.14 | | +1 MW |
| `wind` | 🌬 Wind | 150 | 4 | -0.50 | | +3 MW |
| `green-roof` | 🏡 Gründach | 30 | **0** | -0.04 | | |
| `dike` | 🌊 Deich | 80 | 3 | | +12 cm | |
| `sea-wall` | 🛡 Hochw.schutz | 240 | 6 | | +50 cm | |
| `coal` | 🏭 Kohle | 20 | 1 | **+0.38** | | +4 MW |
| `airport` | ✈️ Flughafen | 62 | 3 | **+0.22** | | |
| `cloud-seed` | 🌤 Wolken-Impfung | 125 | 4.5 | -0.04 | | |
**Differenzierung:**
- **Solar vs Wind:** Solar günstig pro Stück, Wind effizienter pro MW Betrieb
- **Wald:** Günstigste Wartung pro CO₂-ppm (didaktisch: Naturlösung)
- **Gründach:** Einzige Maßnahme mit 0 Wartung (Set-and-forget)
- **Deich vs Hochwasserschutz:** Niedrige Hürde vs effiziente Großlösung
- **Kohle/Flughafen/Wolken:** Negative oder unwirksame Maßnahmen (Lehrtraps)
### 5.3 DIFFICULTY_LEVELS
```typescript
DIFFICULTY_LEVELS[1] // 🟢 Lernen: 750/220, 3J Schonfrist, ×0.5 Folgen
DIFFICULTY_LEVELS[2] // 🟡 Üben: 550/175, 1J Schonfrist, ×1.0 Folgen
DIFFICULTY_LEVELS[3] // 🔴 Profi: 400/145, 0J Schonfrist, ×1.5 Folgen
```
Beeinflusst: `startBudget`, `incomePer10k`, `blackoutGrace`, `treesPerBlackout`,
`co2BlackoutPerYear`, `climateDamageMul`, `popLossMul`.
### 5.4 Klimaberechnung (`computeClimate()`)
```
targetTemp = computeTemperature(co2Ppm, sensitivity=0.3)
currentTemp += (targetTemp - currentTemp) * 0.08 // Trägheit (Ozean)
sealevelTarget = (currentTemp - 15) * 30 cm/°C
sealevelCm += (target - current) * (rising ? 0.08 : 0.005) // committed rise
floodedHouses = max(0, (sealevel - protection - 35) * 0.9) [%]
```
### 5.5 simulateTick — Reihenfolge
```
1. Steuern (income = popRatio × diff.incomePer10k)
1b. Tourismus (Bonus + CO₂, oder Kollaps wenn Strand weg)
2. Wartung
3. CO₂-Update (emissions - reduction)
4. computeClimate()
4b. Strom-Bilanz + Stromausfall-Folgen (Bäume + CO₂ + Pop-Drift)
5. Häuser-Überflutung
5b. Sealevel-Folgen (Versalzung, Pop-Drift)
6. Zeit-Events
7. Citizen-Events (maybeTriggerCitizenEvent)
```
### 5.6 Citizen Events
| Tick | ID | Trigger |
|---|---|---|
| 15 | `citizen-fisher` | Lina, Fischerin (warmes Wasser) |
| 9 | `citizen-scientist` | Dr. Hassan, Forschungszentrum |
| 14 | `citizen-farmer` | Yusuf, Bewässerung |
| 20 | `citizen-tourism` | Maria, Hotel |
| 28 | `citizen-youth` | Lia, 14, Streik |
| 38 | `citizen-industry` | Konzernchef Vogel |
| 50 | `citizen-mountain` | Anna, Bergdorf |
---
## 6. Auto-Pause-System (in HTML-Seite)
In `game-3d.html` als Token-basiertes Pause-System:
```javascript
const overlayPauseTokens = new Set()
let speedBeforeOverlayPause = 1
function pauseGameForOverlay(token) { ... }
function resumeGameForOverlay(token) { ... }
// Auto-Hooks via MutationObserver:
observeOverlayForPause('.citizen-overlay', 'citizen-event')
observeOverlayForPause('.info-overlay', 'info-overlay')
// Manuell für Graph-Zoom + Events-Popout
```
**Konvention:** Jeder neue Overlay-Typ registriert sich mit eigenem Token.
Beim letzten Schließen wird `speedBeforeOverlayPause` wiederhergestellt.
---
## 7. Konventionen & Best Practices
### 7.1 Tooltip-System
**Globaler Listener:** `installTooltips()` in `info-overlay.ts` registriert
einen delegated `mouseover`-Handler. Jedes Element mit `data-tip="key"`
zeigt automatisch das `TIPS[key]`-Tooltip beim Hover.
```html
<span data-tip="ppm">ppm <span class="unit-i">i</span></span>
```
**Erweitern:** Neuen Eintrag in `TIPS: Record<string, TipDef>` hinzufügen.
### 7.2 Display-Animation
Numeric Resources werden via gedämpfter rAF-Loop (12% pro Frame) zum
Zielwert hingezogen. Implementiert in `GameUI.ensureDisplayAnim()`.
Snapping bei `absDelta < 0.5`.
### 7.3 Graph-Zoom (FLIP-Pattern)
Beim Klick auf eine `.graph-card`:
1. Card via `appendChild(body)` aus Container herauslösen (wegen `backdrop-filter`)
2. Platzhalter im Original-Grid lassen
3. `position: fixed` mit Original-Rect setzen, Reflow erzwingen
4. Transition zu zentrierten Größen
5. Nach Animation `ui.redrawGraphs()` für SVG-Resize
Bei Unzoom: zurück animieren, Card in Platzhalter-Position wieder einfügen,
Inline-Styles aufräumen.
### 7.4 Save-Versionierung
Bei jeder Mechanik-Änderung in einer Sim:
1. `SAVE_VERSION` in `game-engine.ts` erhöhen (oder Sim-spezifisches `SCHEMA_VERSION` falls vorhanden)
2. Alte Saves werden automatisch verworfen
3. UI zeigt freundlichen Hinweis
### 7.5 Trace-Tests
`tests/unit/sim-05-trace.test.ts` simuliert verschiedene Strategien rein
rechnerisch über alle 75 Jahre und prüft, dass:
- Optimale Strategie gewinnt
- "Nichts tun" verliert
- "Nur Wald" verliert (zu langsam)
- "Nur Deich" verliert (CO₂ killt sie trotzdem) — **TODO**: aktuell unsicher
---
## 8. Ranking-System (vorgeschlagen, noch nicht implementiert)
Erweitere `GameMeta` um:
```typescript
interface GameRanking {
complexity: 1|2|3|4|5
timeMinutes: number
gradeRecommendation: { min: number; max: number } // 1-12 Schulstufe
focusedLearning: 1|2|3|4|5
topics: string[]
}
```
### Klimawächter (sim-05) Vorschlag:
```typescript
ranking: {
complexity: 4,
timeMinutes: 15,
gradeRecommendation: { min: 6, max: 8 },
focusedLearning: 3,
topics: ['Klimawandel', 'Energiewende', 'Anpassung vs Mitigation', 'Wirtschaftsbilanz']
}
```
`index.html` filtert/sortiert dann Sims nach Ranking.
---
## 9. Offene Punkte (kurzgefasst)
| Was | Wo dokumentiert |
|---|---|
| Phase B: Drag-and-Drop-Baueditor | dev-log §4 |
| Phase C: Wohnungsbau + Neuankömmlinge | dev-log §4 |
| Mitigation vs Adaptation Kipppunkt | dev-log §4 (idee) |
| Insel-Leben Sprites (Wolken, Möwen, Boote) | brainstorm offen |
| Sand-Aufschüttung mit Erosion | brainstorm offen |
| Mangroven (Win-Win-Maßnahme) | brainstorm offen |
| Sterne-Ranking implementieren | dieses Dok §8 |
| 2D-Renderer auf Strom-System updaten | dev-log §8 |
---
## 10. Konventionen für die KI
Wenn die KI Code-Änderungen macht:
1. **Erst lesen, dann ändern.** Nie Annahmen über Code, der nicht im Kontext ist.
2. **Build + Tests nach jeder Änderung.** `npx vite build && npx vitest run`.
3. **Headless-Verify für UI-Änderungen.** Playwright-Script in `App/scripts/`.
4. **Save-Schema bei Mechanik-Änderung erhöhen.** Sonst kaputte Saves.
5. **Trace-Test grün halten.** Wenn er rot wird: Balance kalibrieren, nicht ignorieren.
6. **Diese Doku aktualisieren** bei Schnittstellen-Änderungen.
7. **Wald = günstigste CO₂-Reduktion pro Mio €.** Heilig. Nie verschlechtern.
8. **Mio €** ist die Geldeinheit. Nie nackte Euro.
9. **Tick = Jahr** in sim-05. Falls Wechsel auf Monate: alle Werte ÷12.
10. **Einfache emojis bevorzugen** (Single-Codepoint, kein ZWJ). 🧍 ja, 🧍‍♀️ nein.
+296
View File
@@ -0,0 +1,296 @@
# GeoGraSim — Informationsarchitektur & Content-Spezifikation
Dieses Dokument beschreibt die öffentlichen und didaktischen Inhalte von
GeoGraSim (Landing Page, Modul-Detailseiten, Lehrplan-Bezug, Glossar). Es
richtet sich an die Content-Instanz, die diese Seiten erstellt.
---
## 1. Drei Benutzer-Pfade
```
ANONYM SCHÜLER:IN LEHRPERSON
────── ────────── ──────────
Landing Page (index.html) Mein Dashboard Klassen-Dashboard
↓ Überblick (schueler.html) (teacher.html)
↓ "Sofort ausprobieren" ↓ Meine Module ↓ Modulfreigabe
↓ Für Lehrpersonen ↓ Badges, Fortschritt ↓ Ergebnisse
↓ Für Schüler:innen
Profil Lehrplan-Matching
Simulationen-Übersicht (neu, pro Modul)
↓ Cards je Modul Glossar (mit Markierung
"schon gelernt")
Modul-Detailseite (NEU)
↓ Was lerne ich?
↓ Welche Begriffe?
↓ Lehrplan-Bezug
↓ Jetzt probieren
Glossar (wird parallel gebaut)
Lehrplan-Seite (NEU)
↓ AT / DE / CH / LI Filter
↓ Kompetenz-Mapping
↓ Welches Modul passt wohin
```
---
## 2. Kern-Prinzip: Kompetenz-Brücke
**Problem:** DACH+LI haben zusammen ~40 verschiedene Lehrpläne (Bundesländer,
Kantone, Schultypen). Alle einzeln zu pflegen ist nicht leistbar.
**Lösung:** Module werden auf **didaktische Kompetenzbereiche** gemappt, nicht
auf einzelne Lehrpläne. Jeder Lehrplan referenziert ähnliche Kompetenzen — die
Lehrperson erkennt den Bezug selbst.
Beispiel:
```
Kompetenzbereich: "Klimawandel verstehen"
├── Modul: Klimawächter 2D (Level 13)
├── Modul: Klimawächter 3D (Level 13)
└── Lehrplan-Anker:
├── 🇦🇹 AT Mittelschule GW, Kl. 8 — "Anthropogener Klimawandel"
├── 🇩🇪 DE Berlin GL, Kl. 9 — "Klimawandel als globale Herausforderung"
├── 🇨🇭 CH Lehrplan 21, NMG.3.2 — "Klima und Wetter"
└── 🇱🇮 LI 7. Schulstufe GW — "Naturphänomene und Klimasystem"
```
Die Lehrperson sieht: "Ja, passt zu meinem Lehrplan-Punkt" und weiß, dass das
Modul didaktisch fundiert zugeordnet ist.
---
## 3. Datenbank-Schema (Vorschlag — abstimmen mit Zentrale)
```sql
-- Didaktische Kompetenzbereiche (zentrale Brücke)
CREATE TABLE kompetenzen (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
key_slug VARCHAR(64) NOT NULL UNIQUE, -- 'klimawandel', 'raumplanung'
title VARCHAR(128) NOT NULL, -- 'Klimawandel verstehen'
description TEXT, -- Didaktisch ausformuliert (3-5 Sätze)
category VARCHAR(32), -- 'klima', 'raum', 'gesellschaft'
age_min TINYINT UNSIGNED, -- 10 (Klasse 5)
age_max TINYINT UNSIGNED, -- 16 (Klasse 10)
sort_order INT DEFAULT 0
);
-- Modul ↔ Kompetenz (N:M)
CREATE TABLE kompetenz_modules (
kompetenz_id INT UNSIGNED NOT NULL,
module_id VARCHAR(16) NOT NULL, -- 'klima', 'heli', 'fluss', 'stadt'
level TINYINT UNSIGNED, -- 1, 2, 3 (optional)
strength ENUM('primär', 'sekundär') DEFAULT 'primär',
PRIMARY KEY (kompetenz_id, module_id, level),
FOREIGN KEY (kompetenz_id) REFERENCES kompetenzen(id) ON DELETE CASCADE
);
-- Lehrplan-Anker pro Kompetenz
CREATE TABLE lehrplan_anchors (
id INT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
kompetenz_id INT UNSIGNED NOT NULL,
country CHAR(2) NOT NULL, -- 'AT', 'DE', 'CH', 'LI'
region VARCHAR(32), -- Bundesland/Kanton (optional)
school_type VARCHAR(32), -- 'MS', 'AHS', 'Gym', ...
grade VARCHAR(16), -- 'Kl. 8', '7.-8. Stufe'
title VARCHAR(255), -- 'Anthropogener Klimawandel'
reference VARCHAR(255), -- Offizielle Lehrplan-Referenz/URL
quote TEXT, -- Exaktes Zitat aus dem Lehrplan
FOREIGN KEY (kompetenz_id) REFERENCES kompetenzen(id) ON DELETE CASCADE,
INDEX (country, school_type, grade)
);
-- Modul-Metadaten (für Detailseiten)
CREATE TABLE module_info (
module_id VARCHAR(16) NOT NULL PRIMARY KEY,
title VARCHAR(128) NOT NULL, -- 'Klimawächter'
subtitle VARCHAR(255), -- 'Klima retten, Küste schützen'
short_desc TEXT, -- 1-2 Sätze für Card
long_desc TEXT, -- Ausführlich für Detailseite
learning_goals TEXT, -- JSON-Array oder Markdown
duration_min INT UNSIGNED, -- Geschätzte Spieldauer in Minuten
age_min TINYINT UNSIGNED,
age_max TINYINT UNSIGNED,
icon VARCHAR(16), -- Emoji
card_image VARCHAR(255), -- card-climate.png etc.
status ENUM('aktiv', 'beta', 'archiv') DEFAULT 'beta',
sort_order INT DEFAULT 0
);
```
---
## 4. Arbeitsbereich Content-Instanz
### SCHREIBEN
- `App/pages/modul-klima.php` — Detailseite Klimawächter
- `App/pages/modul-heli.php` — Detailseite Heli
- `App/pages/modul-fluss.php` — Detailseite Fluss
- `App/pages/modul-stadt.php` — Detailseite Stadt
- `App/pages/lehrplan.php` — Lehrplan-Übersicht mit Filtern
- `App/pages/simulationen.php` — Übersichtsseite aller Module (ersetzt evtl. eine Section auf der Landing)
- DB-Tabellen: `kompetenzen`, `kompetenz_modules`, `lehrplan_anchors`,
`module_info` (über PHP/PDO, nicht via mysql.exe — Umlaute!)
### LESEN
- Gesamtes Projekt
- `App/docs/module-interface.md`
- `App/docs/content-architecture.md` (dieses Dokument)
- Bestehende Module zum Verstehen des Inhalts
### NICHT ANFASSEN
- Module selbst (`App/sims/...`)
- Glossar (macht die Glossar-Instanz) — aber du darfst Glossar-Einträge per
Inbox an Glossar-Instanz anfragen, wenn sie für Modul-Detailseiten nützlich
sind
- Landing Page (`index.html`, `index.php`) — du darfst Änderungs-Vorschläge
per Zentrale-Inbox schicken, aber nicht selbst editieren
- Design-System, Admin, APIs
---
## 5. Recherche-Quellen für Lehrpläne
### Österreich
- Lehrplan Mittelschule (BMBWF): https://www.bmbwf.gv.at → Unterricht → Lehrpläne
- Lehrplan AHS Unterstufe
- GW (Geographie und Wirtschaftsbildung) steht seit 2023 neu strukturiert
### Deutschland
- Konzentration auf große Bundesländer + neutrale Lehrplan-Kernelemente
- Bildungsstandards KMK (Kultusministerkonferenz) als Dach
- Pro Bundesland evtl. nur 12 Referenzen
### Schweiz
- Lehrplan 21 (21 Kantone, gemeinsame Struktur)
- NMG (Natur, Mensch, Gesellschaft) in Sek I, RZG (Räume, Zeiten, Gesellschaften)
### Liechtenstein
- Eigener Lehrplan, lehnt sich stark an CH an
- Lehrplan FL ab 2012 (LiLe)
### Prinzip der Recherche
**Weniger Tiefe, mehr Breite.** Für jede Kompetenz **35 Anker** aus
verschiedenen Ländern. Nicht alle 16 Bundesländer + 26 Kantone einzeln. Die
Lehrperson muss das Modul als lehrplankonform erkennen, nicht den exakten
Paragrafen finden.
---
## 6. Modul-Detailseiten: Struktur
Jede Modul-Detailseite (z.B. `modul-klima.php`) hat:
```
┌────────────────────────────────────────────────┐
│ HEADER (bildLogo + textlogo + Navi) │
├────────────────────────────────────────────────┤
│ │
│ HERO-BEREICH │
│ ┌──────────┐ 🌍 KLIMAWÄCHTER │
│ │ Card-Bild│ Klima retten, Küste schützen. │
│ │ (DALL-E) │ [Sofort probieren] │
│ └──────────┘ [Für Lehrpersonen: Lehrplan- │
│ Bezug] │
│ │
│ META-ANGABEN │
│ Dauer: 30-45 Min · Alter: 12-16 · 3 Levels │
│ │
├────────────────────────────────────────────────┤
│ WAS LERNST DU? │
│ [Lernziel 1] [Lernziel 2] [Lernziel 3] │
│ (Aus learning_goals, als Bullet-Liste) │
│ │
├────────────────────────────────────────────────┤
│ WIE FUNKTIONIERT'S? │
│ Ausführliche Beschreibung der Spielmechanik, │
│ evtl. mit Screenshots / GIFs │
│ │
├────────────────────────────────────────────────┤
│ BEGRIFFE DIE DU KENNENLERNST │
│ (Aus glossar-Tabelle: alle Einträge │
│ mit module='klima') │
│ [CO₂] [ppm] [Watt] [Megawatt] [Windpark] ... │
│ → Kleine Chips mit Hover-Definition │
│ │
├────────────────────────────────────────────────┤
│ LEHRPLAN-BEZUG │
│ [🇦🇹] [🇩🇪] [🇨🇭] [🇱🇮] │
│ │
│ Kompetenzbereich: Klimawandel verstehen │
│ → AT MS GW Kl. 8: "Anthropogener Klimawandel"│
│ → DE Berlin GL Kl. 9: "Klimawandel global" │
│ → CH NMG.3.2: "Klima und Wetter" │
│ │
├────────────────────────────────────────────────┤
│ FOOTER (wie alle Seiten) │
└────────────────────────────────────────────────┘
```
---
## 7. Lehrplan-Übersichtsseite (`lehrplan.php`)
```
┌────────────────────────────────────────────────┐
│ HEADER │
├────────────────────────────────────────────────┤
│ LEHRPLAN-BEZUG │
│ │
│ Land: [Alle] [🇦🇹 AT] [🇩🇪 DE] [🇨🇭 CH] [🇱🇮 LI]│
│ Stufe: [Alle] [Sek I] [Sek II] │
│ Thema: [Alle] [Klima] [Raum] [Gesellschaft] │
│ │
├────────────────────────────────────────────────┤
│ GRUPPIERT NACH KOMPETENZBEREICH │
│ │
│ ▸ Klimawandel verstehen │
│ 🌍 Klimawächter 2D · 🌍 Klimawächter 3D │
│ 🇦🇹 AT MS GW Kl. 8 — "Anthropogener..." │
│ 🇩🇪 DE Berlin GL Kl. 9 — "Globale..." │
│ 🇨🇭 CH Lehrplan 21 NMG.3.2 │
│ │
│ ▸ Naturgefahren und Hochwasser │
│ 🏞️ Flussmanagement │
│ 🇦🇹 ... 🇩🇪 ... 🇨🇭 ... 🇱🇮 ... │
│ │
│ ▸ Alpine Geografie │
│ 🚁 Heli-Navigation │
│ │
│ ▸ Stadtplanung und Raumordnung │
│ 🏙️ Stadt & Raumplanung │
│ │
└────────────────────────────────────────────────┘
```
---
## 8. Landing-Page-Ergänzungen (Vorschlag an Zentrale)
Die Landing Page (`index.html`) sollte minimal ergänzt werden:
- Link zum Glossar im Footer oder als eigene Section
- Link zur Lehrplan-Seite im Lehrpersonen-Bereich
- Simulations-Cards sollen auf die neuen Modul-Detailseiten verlinken
(nicht direkt ins Spiel) — ausser der Gast probiert direkt
**Du änderst die Landing NICHT selbst** — du schickst einen konkreten
Änderungs-Vorschlag (mit Code-Diff) per Nachricht an `zentrale/`, die
Zentrale integriert das.
---
## 9. Erste Schritte
1. Dieses Dokument lesen
2. DB-Schema vorschlagen / mit Zentrale abstimmen (Inbox-Nachricht)
3. `kompetenzen`, `module_info` etc. per PHP-Script anlegen
4. Ersten Modul-Detailseite (`modul-klima.php`) als Template bauen
5. Die anderen Modul-Seiten nachziehen
6. Lehrplan-Recherche für AT + Lehrplan 21 (CH/LI) starten
7. `lehrplan.php` mit echten Ankern befüllen
Bei Fragen oder DB-Änderungen: Nachricht in `App/sims/_inbox/zentrale/`.
+184
View File
@@ -0,0 +1,184 @@
# Crash-Recovery-Protokoll
Was tun, wenn Windows, VS Code oder der Rechner abstürzen und alle
Claude-Sessions weg sind? Hier die Schritt-für-Schritt-Anleitung.
## Was überlebt einen Absturz immer
- Alle **Code-Dateien** auf der Platte
- Alle **Inbox-Nachrichten** (Markdown in `App/sims/_inbox/`)
- Alle **Memory-Einträge** von Atlas (`~/.claude/projects/.../memory/`)
- Alle **DB-Inhalte** (MySQL)
- Alle **Git-Commits** (lokal im `.git/`-Ordner)
- Die **_status.md** jeder Instanz (siehe unten)
## Was verloren geht
- Der laufende Chat jeder Instanz
- Kontext, den eine Instanz im Kopf hatte (welche Dateien gerade gelesen,
welche Gedanken gerade offen)
---
## Wiederherstellung — Schritt für Schritt
### 1. Atlas (Plattform-Zentrale) reaktivieren
Starte eine neue Claude-Code-Session im Projektordner.
Erster Prompt:
```
Du bist Atlas, die Plattform-Zentrale. Lies als erstes:
1. ~/.claude/projects/c--xampp-htdocs-geograsim/memory/MEMORY.md
2. App/sims/_inbox/zentrale/ (neuste 10 Nachrichten)
Dann melde dich bei mir mit einem Statusbericht: Welche Module aktiv,
welche Aufträge offen, welche Probleme drohen.
```
### 2. Aktive Modul-Instanzen reaktivieren
Für jede Instanz (Klima, Fluss, Glossar, Lehrplan) — neue Session, erster
Prompt:
```
Du bist die {Name}-Instanz im GeoGraSim-Projekt. Lies als erstes:
1. App/sims/_inbox/{ordner}/_status.md (falls vorhanden — aktueller Stand)
2. App/sims/_inbox/{ordner}/ (neuste Nachrichten, chronologisch)
3. App/docs/module-interface.md (wenn du das Interface neu brauchst)
Melde dich dann bei Thomas mit: "Hier {Name}, habe Stand rekonstruiert,
arbeite an {Task}, als nächstes {Next-Step}."
```
Mapping Name → Ordner:
- **Atlas** → `_inbox/zentrale/`
- **Klima** → `_inbox/klima/`
- **Glossar** → `_inbox/glossar/`
- **Lehrplan** → `_inbox/content/`
- **Fluss** → `_inbox/fluss/`
### 3. Git-Stand prüfen
```bash
cd c:/xampp/htdocs/geograsim
git status
git log --oneline -10
```
Falls uncommittete Änderungen da sind: die Instanz, die dran war, muss
entscheiden, ob sie sie übernimmt oder verwirft. Im Zweifel **erst
committen**, dann Instanz Stand lesen lassen.
### 4. Prüfe auf laufende Background-Tasks
Manchmal laufen Python-Scripts (Audio-Generierung, DB-Seeds) im Hintergrund.
Nach Crash sind die tot — einfach neu starten.
---
## Status-Datei `_status.md`
Jede Instanz führt eine `_status.md` in ihrer eigenen Inbox. Struktur:
```markdown
---
instanz: klima
zuletzt_aktualisiert: 2026-04-18 22:45
session_id: informell (z.B. "engine-refactor-phase-1")
---
# Aktueller Stand
## Wo ich stehe
Schritt 2 fertig (Engine extrahiert, 2D umgestellt).
Schritte 3-5 (3D V2) offen.
## Zuletzt geänderte Dateien
- App/sims/klima/engine.js (neu)
- App/sims/klima/game-2d.html (refactored, 515 Zeilen)
## Als nächstes
Schritt 3: game-3d.html V2 aufbauen, Three.js per CDN, Three.js-Szene
aus V1 portieren.
## Offene Entscheidungen
- 2D/3D-Toggle auf modul-klima.php (mit Lehrplan abstimmen)
## Blocker
Keine.
```
**Updates:**
- Bei jedem grösseren Fortschritt überschreiben (nicht append)
- Am Session-Ende definitiv aktualisieren
- Bei Pause/Übergabe ebenfalls
**Atlas pflegt seine Status-Datei in `_inbox/zentrale/_status.md`.**
---
## Commit-Konvention
### Wer committet
- **Atlas** committet projektweite Änderungen (Design-System, APIs, Admin,
gemeinsame Docs)
- **Jede Modul-Instanz** committet ihre eigenen Änderungen
(App/sims/<modul>/*, App/pages/<modul>*.php, modul-spezifische Assets)
### Wann committen
**Pflicht:**
- Am Ende jeder Arbeits-Session (auch wenn unfertig)
- Nach jedem bedeutenden Meilenstein (neues Feature, Phase abgeschlossen)
- Vor jedem Kontext-Wechsel (neue Session übernimmt)
**Empfohlen:**
- Täglich mindestens einmal
- Nach grösseren Refactorings
- Bevor riskante Experimente starten
### Commit-Message-Format
```
<Instanz>: <Kurzbeschreibung>
<Längere Erklärung falls nötig — was und warum>
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
```
Beispiele:
```
Klima: Engine extrahiert (Schritt 1-2)
Klima: WIP 3D V2, Three.js-Setup + Insel-Geometrie
Fluss: Phase 1 fertig - PHP-Wrapper + leeres Canvas
Atlas: Music-Registry erweitert um Drama-Slot
Glossar: 5 Repräsentationsbilder im Querformat
```
### Commit-Befehl
```bash
cd c:/xampp/htdocs/geograsim
git add <dateien>
git commit -m "<Instanz>: <Kurzbeschreibung>"
# Kein push — lokal reicht (kein Remote eingerichtet)
```
---
## Optional: Remote-Backup
Momentan **kein Remote** eingerichtet. Bei Festplatten-Defekt wäre alles
verloren. Möglichkeiten (entscheidet Thomas):
1. **Eigener Server** (geograsim.at hat SSH): Meister-Instanz kann ein
Bare-Repo in `/root/git/geograsim.git` einrichten. Dann `git push`
als Backup.
2. **Externe Platte**: `robocopy` nach USB-HDD, täglich.
3. **Keine Cloud-Dienste** (Thomas hat GitHub abgelehnt).
Atlas schlägt vor, irgendwann Option 1 einzurichten. Nicht akut, aber
planbar.
+485
View File
@@ -0,0 +1,485 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Klimawächter — Entwicklungs-Log</title>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet">
<style>
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
:root {
--bg: #f7f6f3; --bg2: #efeee9; --white: #fff;
--text: #1a1a1a; --text2: #4a4a4a; --text3: #8a8a8a;
--fjord: #4a7c8a; --fjord-l: #dae8ec; --fjord-d: #3a6470;
--moss: #5a8a5e; --moss-l: #dceadd;
--sand: #c4a35a; --sand-l: #f2eacc;
--coral: #c07a6b; --coral-l: #f2ddd8;
--danger: #b04a3a;
}
body {
font-family:'Inter',system-ui,sans-serif; background:var(--bg);
color:var(--text); line-height:1.6; padding:2rem 1rem;
}
.w { max-width: 880px; margin: 0 auto; }
header {
border-bottom: 3px solid var(--fjord); padding-bottom: 1.2rem; margin-bottom: 2rem;
}
h1 { font-size: 2rem; font-weight: 900; color: var(--fjord); margin-bottom: .3rem; }
header .sub { font-size: .9rem; color: var(--text3); font-weight: 500; }
h2 {
font-size: 1.4rem; font-weight: 800; color: var(--fjord-d);
margin: 2.2rem 0 .8rem; padding-top: 1rem;
border-top: 1px solid rgba(0,0,0,.08);
}
h3 { font-size: 1.05rem; font-weight: 700; color: var(--text); margin: 1.2rem 0 .5rem; }
p { font-size: .95rem; color: var(--text2); margin-bottom: .8rem; }
ul, ol { margin: .5rem 0 1rem 1.4rem; }
li { font-size: .93rem; color: var(--text2); margin-bottom: .35rem; }
code {
background: var(--bg2); padding: 1px 6px; border-radius: 4px;
font-size: .85em; font-family: "SF Mono", Menlo, monospace;
color: var(--fjord-d);
}
pre {
background: #1a1a1a; color: #e8e6de; padding: 1rem 1.2rem;
border-radius: 10px; font-size: .82rem; overflow-x: auto;
font-family: "SF Mono", Menlo, monospace; margin: .8rem 0 1.2rem;
}
.card {
background: var(--white); border: 1px solid rgba(0,0,0,.06);
border-radius: 12px; padding: 1.1rem 1.3rem; margin: .8rem 0;
box-shadow: 0 2px 8px rgba(0,0,0,.03);
}
.card.green { border-left: 4px solid var(--moss); }
.card.sand { border-left: 4px solid var(--sand); }
.card.coral { border-left: 4px solid var(--coral); }
.card.fjord { border-left: 4px solid var(--fjord); }
.card h3 { margin-top: 0; }
.tag {
display: inline-block; font-size: .68rem; font-weight: 700;
padding: 2px 8px; border-radius: 6px;
background: var(--fjord-l); color: var(--fjord-d);
text-transform: uppercase; letter-spacing: .05em;
margin-right: .3rem;
}
.tag.done { background: var(--moss-l); color: var(--moss); }
.tag.todo { background: var(--sand-l); color: var(--sand); }
.tag.idea { background: var(--coral-l); color: var(--danger); }
table {
width: 100%; border-collapse: collapse; margin: .8rem 0 1.2rem;
font-size: .85rem;
}
th, td {
text-align: left; padding: .55rem .7rem;
border-bottom: 1px solid rgba(0,0,0,.08);
}
th { background: var(--bg2); font-weight: 700; color: var(--text); }
.quote {
border-left: 3px solid var(--fjord);
background: var(--fjord-l);
padding: .6rem .9rem;
border-radius: 0 8px 8px 0;
font-style: italic;
color: var(--fjord-d);
margin: .5rem 0 1rem;
font-size: .9rem;
}
nav.toc {
background: var(--bg2); border-radius: 10px; padding: 1rem 1.3rem; margin-bottom: 2rem;
}
nav.toc h4 {
font-size: .7rem; font-weight: 800; color: var(--fjord); text-transform: uppercase;
letter-spacing: .06em; margin-bottom: .5rem;
}
nav.toc ol { margin-left: 1.2rem; }
nav.toc a {
color: var(--text2); text-decoration: none; font-size: .88rem;
}
nav.toc a:hover { color: var(--fjord); }
footer {
margin-top: 3rem; padding-top: 1.5rem;
border-top: 1px solid rgba(0,0,0,.08);
font-size: .8rem; color: var(--text3); text-align: center;
}
</style>
</head>
<body>
<div class="w">
<header>
<h1>Klimawächter — Entwicklungs-Log</h1>
<div class="sub">Erkenntnisse, offene Punkte und nächste Schritte · Stand 2026-04-11 (3 Schwierigkeitsgrade + Bilanz + Steg-Rampe)</div>
</header>
<nav class="toc">
<h4>Inhalt</h4>
<ol>
<li><a href="#ziel">Didaktisches Ziel und Zielgruppe</a></li>
<li><a href="#architektur">Architektur-Überblick</a></li>
<li><a href="#mechanik">Mechanik-Erkenntnisse aus Trace-Tests</a></li>
<li><a href="#ui">UI / Interaktion</a></li>
<li><a href="#visual">Visualisierung (2D / 3D)</a></li>
<li><a href="#erklaerungen">Erklärungen für Kinder 1014</a></li>
<li><a href="#folgen">Weitere Folgen des Klimawandels</a></li>
<li><a href="#offen">Offene Punkte & nächste Schritte</a></li>
</ol>
</nav>
<!-- ====================================================== -->
<section id="ziel">
<h2>1. Didaktisches Ziel und Zielgruppe</h2>
<p>Der <strong>Klimawächter</strong> ist kein Spiel um einen high score. Er soll Schülerinnen und Schülern der 1.4. Klasse Sekundarstufe I (ca. <strong>1014 Jahre</strong>) vermitteln, dass:</p>
<ul>
<li>der Klimawandel träge ist — Folgen kommen verzögert, Entscheidungen wirken erst in Jahren</li>
<li>es keine Wunderlösung gibt — man muss mehrere Strategien kombinieren</li>
<li>reine Anpassung (Deiche, Strandaufschüttung) die Ursache nicht löst</li>
<li>Klimaschutz kein isoliertes Naturthema ist — gesellschaftliche Konflikte gehören dazu</li>
<li>eine Insel stellvertretend für den Planeten stehen kann</li>
</ul>
<div class="quote">
Kinder haben typischerweise Fehlkonzepte wie „Ozonloch = Klimawandel" oder „Wenn ich hier einen Baum pflanze, ist alles gut". Das Spiel arbeitet dezent dagegen an.
</div>
</section>
<!-- ====================================================== -->
<section id="architektur">
<h2>2. Architektur-Überblick</h2>
<div class="card fjord">
<h3>Frontend-Stack</h3>
<ul>
<li><code>TypeScript + Vite</code> (keine Framework-Schicht)</li>
<li><code>Three.js</code> für die 3D-Version</li>
<li>2D-Version nutzt Canvas-API direkt</li>
<li>Multi-Page HTML (<code>game.html</code>, <code>game-3d.html</code>, <code>erdbeben.html</code>, <code>energiemix.html</code>)</li>
</ul>
</div>
<div class="card fjord">
<h3>Kernklassen</h3>
<table>
<tr><th>Datei</th><th>Rolle</th></tr>
<tr><td><code>src/core/game-engine.ts</code></td><td>Abstract base: Ticks, Resources, Goals, Save/Load, Subscribe-Pattern, Citizen-Events</td></tr>
<tr><td><code>src/ui/game-ui.ts</code></td><td>Wiederverwendbare UI-Komponente mit Panels, Graphen, Auto-Save, End-Screen</td></tr>
<tr><td><code>src/ui/info-overlay.ts</code></td><td>Kindgerechte Begriffserklärungen (Info-Buttons öffnen Overlay)</td></tr>
<tr><td><code>src/sims/sim-05-treibhaus/game.ts</code></td><td>Klimawächter-Spiellogik</td></tr>
<tr><td><code>src/sims/sim-05-treibhaus/game-renderer.ts</code></td><td>2D-Canvas-Renderer</td></tr>
<tr><td><code>src/sims/sim-05-treibhaus-3d/game-renderer-3d.ts</code></td><td>Three.js 3D-Renderer</td></tr>
</table>
</div>
<div class="card fjord">
<h3>Save-System</h3>
<p>Alle Spielstände werden pro Spiel-ID in <code>localStorage</code> persistiert. Version-Bump (v2) verhindert, dass alte inkonsistente Saves geladen werden. Ein <code>resetting</code>-Flag verhindert, dass der <code>beforeunload</code>-Handler beim Reset sofort wieder speichert.</p>
</div>
</section>
<!-- ====================================================== -->
<section id="mechanik">
<h2>3. Mechanik-Erkenntnisse aus Trace-Tests</h2>
<p>Es existiert ein automatischer Test unter <code>tests/unit/sim-05-trace.test.ts</code>, der das Spiel rein rechnerisch über 75 Jahre für verschiedene Strategien durchspielt und die Werte tabellarisch ausdruckt. Starten mit:</p>
<pre>npx vitest run sim-05-trace --reporter=verbose</pre>
<h3>Balance-Status (aktuell kalibriert)</h3>
<table>
<tr><th>Strategie</th><th>Ergebnis 2100</th><th>Status</th></tr>
<tr><td>Nichts tun</td><td>Temp 17.9°C, Flut 52%</td><td></td></tr>
<tr><td>Nur Wälder</td><td>Temp 17.1°C</td><td>❌ (knapp)</td></tr>
<tr><td>Nur Solar</td><td>Temp 15.5°C, Budget knapp</td><td></td></tr>
<tr><td>Nur Wind</td><td>Temp 15.5°C, Budget ok</td><td></td></tr>
<tr><td>Nur Deiche</td><td>Temp 17.9°C — Klima läuft durch</td><td></td></tr>
<tr><td>Wälder + Solar</td><td>grenzwertig — meist verloren</td><td>⚠️</td></tr>
<tr><td>Solar + Wind + 1 Deich</td><td>alle Goals ✅</td><td></td></tr>
</table>
<div class="card sand">
<h3>Didaktische Aussagen, die aus dem Trace sichtbar werden</h3>
<ul>
<li>Einzelmaßnahme = zu wenig. Man muss kombinieren.</li>
<li>Deiche allein retten kurzfristig Häuser, aber nicht das Klima.</li>
<li>Aufforsten ist wichtig, aber als Einzelmaßnahme zu langsam.</li>
<li>Wind ist stärker als Solar, aber wegen Wartungskosten nicht immer die beste Wahl.</li>
<li>Das Klima hat eine Trägheit von ca. 8 %/Jahr für Temperatur und 68 %/Jahr für Meeresspiegel.</li>
</ul>
</div>
<h3>Bug-Historie (chronologisch)</h3>
<ol>
<li><strong>Subclass-Felder nicht im Save</strong> → Werte driften zwischen UI und Rechnung. <em>Fix: <code>serializeSubclass()</code> Hook.</em></li>
<li><strong>Wasser stand still im 3D-Renderer</strong> → Protection wurde von waterY abgezogen. <em>Fix: Wasser steigt jetzt absolut, Protection wirkt nur auf Submerge-Check der Häuser.</em></li>
<li><strong>Solar überpowered</strong> → CO₂ fiel unter vorindustriell. <em>Fix: Maßnahmen-Reduktion halbiert, CO₂-Floor 350 ppm.</em></li>
<li><strong>Reset-Button ohne Wirkung</strong> → beforeunload schrieb Stand wieder ins localStorage. <em>Fix: <code>resetting</code>-Flag.</em></li>
</ol>
</section>
<!-- ====================================================== -->
<section id="ui">
<h2>4. UI / Interaktion</h2>
<div class="card green">
<h3><span class="tag done">done</span> Auto-Save</h3>
<p>Jede Aktion → debounced Save nach 1.5 s. Sofortiges Save bei Tab-Wechsel oder Page-Verlassen. Auto-Load beim erneuten Öffnen.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Bürger-Beschwerden mit Choices</h3>
<p>Modaler Dialog mit Avatar, Message und 23 Choice-Karten. Jede Wahl hat echte Konsequenzen. Spiel pausiert automatisch bis der Spieler entscheidet. Bibliothek: 7 Events über die 75 Jahre verteilt (Fischerin, Forscherin, Bauer, Hotel, Jugend-Streik, Industrie, Bergdorf).</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Reset-Button</h3>
<p>Im Header oben rechts (🔄). Löscht den Save-Slot und lädt die Seite neu.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Header-Refactor</h3>
<p>Save/Load/Finish/Reset/Home sind jetzt reine Symbole mit Tooltips. Speed-Buttons mit Zahlen (×1, ×2, ×4) und Kamera-Controls (, , ⊙) sind in den Header gewandert. Das spart Platz unten und macht die Graphen größer.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Guided / Free Mode</h3>
<p>GameUI unterstützt <code>mode: 'guided'</code> mit <code>totalDurationSec</code>. Im Guided-Mode wird <code>msPerTick</code> automatisch so gesetzt, dass das Spiel genau die vorgegebene Zeit dauert, und Speed-Buttons &gt; 1 sind unsichtbar. Bereit für späteres Lehrer-Backend.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Strom-System (Phase A der SimCity-Erweiterung)</h3>
<p>Neue Ressource <code>⚡ Strom</code>, Anzeige als „Bedarf/Kapazität MW" in der Status-Box. Bedarf = 1 MW pro 1.000 Einwohner. Kapazität ergibt sich aus den gebauten Kraftwerken:</p>
<ul>
<li><strong>☀️ Solar</strong> = +1 MW (klein, sauber)</li>
<li><strong>🌬️ Wind</strong> = +3 MW (mittel, sauber, teuer)</li>
<li><strong>🏭 Kohle</strong> = +8 MW (sofort viel Strom — aber +1.5 ppm CO₂/Jahr)</li>
</ul>
<p>Bei Stromausfall (Bedarf &gt; Kapazität): siehe nächste Karte.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> „Bäume verheizen" bei Stromausfall</h3>
<p>Wenn der Strom ausfällt, fällen die Bewohner pro Jahr 2 Bäume und verheizen das Holz. Konsequenzen:</p>
<ul>
<li>+0.6 ppm CO₂ pro Jahr (Holzfeuer)</li>
<li>Bäume gehen sichtbar ins „dead"-Stadium über (schwarzer Strunk, Totenkopf-Sprite)</li>
<li>Tote Bäume binden kein CO₂ mehr → langfristig schlimmer</li>
<li>Ab 3. Stromausfall-Jahr in Folge: Bevölkerung wandert ab</li>
</ul>
<p>Game führt einen Counter <code>treesChoppedForHeat</code>; Renderer liest ihn pro Frame und tötet die Differenz an lebendigen Bäumen.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Maßnahme abreißen (50 % Rückzahlung)</h3>
<p>Neue Methode <code>game.demolishMeasure(id)</code>. UI: 🗑-Button auf jeder Karte mit count&gt;0. Renderer entfernt das zuletzt platzierte Mesh, gibt Geometrie/Material frei. Erlaubt Reparatur falscher Frühentscheidungen (z.B. Kohlekraftwerk wieder loswerden, sobald Wind genug liefert).</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Lina Fischerin nach hinten verschoben</h3>
<p>Citizen-Event „Lina, die Fischerin" war auf Tick 4 — viel zu früh. Ist jetzt auf Tick 15 (≈ 1 Minute Spielzeit). Spieler kann zuerst seine Strom-Versorgung in den Griff bekommen, bevor das erste Bürger-Dilemma kommt.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Drei Schwierigkeitsgrade (Lernen / Üben / Profi)</h3>
<p>Ein <code>DifficultyConfig</code>-System mit 3 Levels (🟢/🟡/🔴) bestimmt Startbudget, Steuern, Stromausfall-Schonfrist und die Härte der Klima-Folgen. Spieler wählt beim ersten Start in einem Selector-Overlay; danach klickt er das Level-Badge oben in der Topbar, um zu wechseln (mit Bestätigung, weil das Spiel neu startet).</p>
<ul>
<li><strong>🟢 Lernen:</strong> 750 Mio € Start, 220 €/10k, 3 Jahre Schonfrist, halbe Klima-Folgen — sehr viel Puffer</li>
<li><strong>🟡 Üben:</strong> 550 Mio €, 175 €/10k, 1 Jahr Schonfrist — Standard, Strategie nötig</li>
<li><strong>🔴 Profi:</strong> 400 Mio €, 145 €/10k, 0 Schonfrist, 1.5× Klima-Folgen — kein Spielraum</li>
</ul>
<p>URL-Parameter <code>?level=N</code> erzwingt ein Level (für späteren Lehrer-Override). Save-File enthält das Level für Resume.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Maßnahmen halbiert (zweite Runde) + Wald-Wartung-Fix</h3>
<p>Alle Maßnahmen-Werte (Cost, Upkeep, CO₂-Wirkung, Schutz) erneut halbiert — gleicher Effekt pro Mio €, aber doppelt so viele individuelle Bauschritte. Mehr Streuung, mehr Spielmöglichkeiten.</p>
<p>Wald-Upkeep zusätzlich auf <strong>0.5 Mio €/Jahr</strong> reduziert (statt 1) — damit ist Wald jetzt die <strong>günstigste Option pro CO₂-Reduktion</strong> (12.5 Mio €/ppm vs Wind 15, Solar 17.9). Das passt zur didaktischen Erwartung „Bäume sind die Naturlösung".</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Jahres-Bilanz unter Budget</h3>
<p>Kleine Tabelle direkt unter dem Budget-Wert in der Status-Box zeigt: + Steuern, (+ Tourismus), Wartung, ( Klima-Schaden), = Netto pro Jahr. Tourism- und Klima-Zeilen sind dynamisch sichtbar. Netto wird grün/rot gefärbt. Lebt mit der gedämpften Display-Animation.</p>
<p>Hat in der ersten Spielanalyse sofort sichtbar gemacht, dass eine Bilanz von 9 Mio €/Jahr auf Dauer nicht überleben kann.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Steg mit Rampe ans Land</h3>
<p>Der Holzsteg am vorderen Strand hat jetzt eine schräge <strong>Holz-Rampe</strong>, die vom Inland-Niveau (auf der Insel selbst) hochsteigt zur Plankenkante (Y=0.85). Damit bleibt der Steg auch bei steigendem Meeresspiegel über die Rampe erreichbar. Die Rampe sitzt physisch auf dem Inselhang und wird vom Wasser nicht überspült.</p>
</div>
<div class="card sand">
<h3><span class="tag idea">idee</span> Mitigation vs. Adaptation — didaktische Diskussion</h3>
<p>Aktuell könnte ein Spieler theoretisch nur Deiche/Hochwasserschutz bauen und ignorieren, dass CO₂ die Ursache ist — solange Temperatur knapp unter 17 °C bleibt. Das vermittelt die falsche Lektion „Mauern reichen". Ideen zum Adressieren:</p>
<ul>
<li><strong>Kipppunkt:</strong> Ab Sealevel &gt; 80 cm sind Deiche nicht mehr genug — sie reißen bei Sturmflut</li>
<li><strong>Wartung steigt mit Sealevel:</strong> Erosion macht Deiche teurer im Unterhalt</li>
<li><strong>Trace-Test:</strong> „Nur-Deich-Strategie" muss langfristig verlieren</li>
</ul>
<p>Wichtig für die nächste Iteration — adressiert die Kernfrage „Sind Deiche wirklich eine gute Lösung?" (Antwort: nur als Pflaster, nicht als Heilung).</p>
</div>
<div class="card sand">
<h3><span class="tag todo">todo</span> Drag-and-Drop Platzierung — Phase B (kurzfristig!)</h3>
<p>Option A aus dem ursprünglichen Interaktions-Konzept. Maßnahmen werden aus dem Shop auf die 3D-Insel gezogen, statt automatisch platziert. Standortabhängige Wirkung: Solar im Vulkan-Schatten = 20% Effizienz, Wind am Hang = +20% etc.</p>
<p><strong>Voraussetzung für Phase C (Wohnungsbau):</strong> Sobald Schüler Häuser kauft, muss er sie auch SETZEN können — sonst frustrierend.</p>
</div>
<div class="card sand">
<h3><span class="tag todo">todo</span> Wohnungsbau + Neuankömmlinge — Phase C</h3>
<p>SimCity-artige Bevölkerungsdynamik:</p>
<ul>
<li>Start mit ~10 Häusern statt 18 (heute schon 6.000 Einwohner statt 10.000)</li>
<li>Neue Maßnahme <strong>🏘 Wohnhäuser</strong> (cost 120, +1.000 Kapazität, +1 MW Bedarf)</li>
<li>Neuankömmlinge-Queue: pro Tick wollen X Familien zuziehen — kommen nur, wenn freie Wohnungen UND Strom da sind</li>
<li>Visuell: 2-3 wandernde Sprite-Figuren am Strand (Billboards wie das Boot)</li>
<li>Tutorial gestaffelt: erst Strom (Phase A), dann Bauen (Phase B), dann Wohnen (Phase C)</li>
</ul>
</div>
<div class="card sand">
<h3><span class="tag todo">todo</span> Krisen-Mini-Spiele</h3>
<p>Bei Sturmflut, Hitzewelle, Murenabgang ein kurzes (1020 s) Klick-Mini-Spiel. Erfolg mildert den Schaden.</p>
</div>
</section>
<!-- ====================================================== -->
<section id="visual">
<h2>5. Visualisierung (2D / 3D)</h2>
<div class="card green">
<h3><span class="tag done">done</span> Insel als Keil (schrägansteigend)</h3>
<p>Beide Renderer (2D und 3D) bilden die Insel nicht mehr als Pfannkuchen ab, sondern als geneigtes Plateau. Die vordere (niedrige) Seite taucht absichtlich ins Wasser — so ist schon am Start sichtbar, dass man nicht die ganze Insel retten kann.</p>
<ul>
<li><strong>3D:</strong> Ellipse, per PlaneGeometry aus 80×96 Segmenten, mit Noise-Verformung und Keil-Interpolation von 1.3 (hinten) nach 0.15 (vorne).</li>
<li><strong>2D:</strong> horizontaler Side-View, linke Seite hoch (Vulkan), rechts niedrig ins Meer. <code>landSurface(x)</code>-Helper interpoliert Y-Koordinate für Platzierung von Häusern, Bäumen, Solaranlagen.</li>
</ul>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Vulkan mit Gletscher-Deckel</h3>
<p>Im 3D-Renderer steht ein erloschener Vulkan am hohen Ende der Insel. Sein oberes Drittel ist von einem opaken Gletscher-Deckel bedeckt. Der Deckel schrumpft mit steigender Temperatur:</p>
<ul>
<li>15.0 °C → 100 % Eis</li>
<li>16.5 °C → 50 % Eis</li>
<li>18.0 °C → 0 % Eis (kahler Fels)</li>
</ul>
<p>Im 2D-Renderer wird derselbe Gletscher-Deckel als Trapez mit Alpha-loser Farbverschiebung dargestellt.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Heizwolken über Häusern ohne Solar</h3>
<p>Jedes Starthaus im 3D hat eine kleine graue Sphere-Wolke über dem Dach. Sobald der Spieler Solar oder Gründächer baut, verschwindet pro Anlage eine Wolke. Direkte visuelle Verbindung zwischen Maßnahme und Effekt.</p>
</div>
<div class="card green">
<h3><span class="tag done">done</span> Graphen mit Zonen und Referenzlinien</h3>
<p>Die neue <code>GraphConfig</code> unterstützt:</p>
<ul>
<li><strong>Farbbänder</strong> (z. B. "Klimaziel", "Kritisch", "Gefahr" bei Temperatur)</li>
<li><strong>Horizontale Referenzlinien</strong> (z. B. "Klimaziel 17°C", "Strand", "Häuser")</li>
<li><strong>Sinnvolle Y-Range</strong> pro Graph — ausreizen der Höhe statt Standard 0..1</li>
<li><strong>Live-Wert</strong> als farbiger Badge rechts oben</li>
</ul>
<p>Graphen sind jetzt etwa doppelt so groß wie vorher (90 px statt ca. 36 px Höhe).</p>
</div>
<div class="card sand">
<h3><span class="tag idea">idee</span> Weitere Visualisierungs-Ideen</h3>
<ul>
<li>Strand schrumpft mit steigendem Meer sichtbar</li>
<li>Mangroven-Streifen am Rand, die bei Sealevel&gt;20 cm verfärben/sterben</li>
<li>Verstreute Tote-Pflanzen-Sprites auf überschwemmtem Gebiet</li>
<li>Vulkan kann bei &gt;18°C tatsächlich „Lava" aus dem Krater drücken (Kipppunkt)</li>
</ul>
</div>
</section>
<!-- ====================================================== -->
<section id="erklaerungen">
<h2>6. Erklärungen für Kinder 1014</h2>
<p>Das neue <code>info-overlay.ts</code>-Modul bietet eine Bibliothek kindgerechter Erklärtexte. Jeder Graph und jedes wichtige Event hat einen (i)-Button, der ein Overlay öffnet. Zielgruppe: 1014 Jahre, einfache Sätze, max. 3 Absätze plus "Merksatz".</p>
<h3>Bisher erklärte Begriffe</h3>
<ul>
<li><strong>CO₂</strong> — Was es ist, wie es wirkt, warum 420 ppm gefährlich sind</li>
<li><strong>Temperatur</strong> — Durchschnittstemperatur, Pariser Ziel, was 2°C bedeuten</li>
<li><strong>Meeresspiegel</strong> — Warum er steigt (Wärmeausdehnung + Eis), Inselstaaten</li>
<li><strong>Budget</strong> — Wie Einnahmen/Wartung funktionieren</li>
<li><strong>Gletscher</strong> — Was sie sind, wie sie schmelzen, warum das Trinkwasser fehlt</li>
<li><strong>Insel-Keilform</strong> — Warum echte Inseln nicht flach sind</li>
<li><strong>Deich</strong> — Wie er funktioniert, Niederlande, "Anpassung" vs. Ursachenbekämpfung</li>
<li><strong>Solar / Wind / Wald</strong> — Jeweils wie sie wirken und warum alleine nicht reichen</li>
<li><strong>Vegetation stirbt durch Salzwasser</strong> — Versalzung, konkretes Beispiel Kenia</li>
<li><strong>Trinkwasser</strong> — Süßwasser-Brunnen auf Inseln, salzige Vermischung</li>
</ul>
<div class="quote">
Alle Texte sind in <code>src/ui/info-overlay.ts</code> als <code>INFO_TOPICS</code>-Objekt zentralisiert und können leicht ergänzt werden. Aufruf: <code>openInfoOverlay(INFO_TOPICS.co2)</code>
</div>
</section>
<!-- ====================================================== -->
<section id="folgen">
<h2>7. Weitere Folgen des Klimawandels</h2>
<p>Bisher hat das Spiel folgende Folgen von Temperatur- und Meeresspiegelanstieg modelliert:</p>
<table>
<tr><th>Folge</th><th>Auslöser</th><th>Wirkung</th></tr>
<tr><td>Häuser werden überflutet</td><td>Sealevel > 35 cm (nach Protection)</td><td>Bevölkerungsrückgang</td></tr>
<tr><td>Vegetation stirbt (Mangroven, Felder)</td><td>Sealevel > 20 cm</td><td>Warn-Event mit Info-Overlay</td></tr>
<tr><td>Trinkwasser versalzt</td><td>Sealevel > 35 cm</td><td>Budget-Abzug pro Jahr + Bevölkerungsrückgang</td></tr>
<tr><td>Gletscher schmilzt</td><td>Temp > 16.8 °C</td><td>Warn-Event, visueller Schrumpf</td></tr>
<tr><td>Bergdorf gefährdet</td><td>Temp > 16.5 °C (Tick 50)</td><td>Citizen-Event (Anna vom Bergdorf)</td></tr>
</table>
<div class="card sand">
<h3><span class="tag idea">idee</span> Noch fehlende Folgen</h3>
<ul>
<li><strong>Korallenbleiche</strong> — Meereswärme &gt; +1.5°C → Fisch-Ertrag sinkt → Budget</li>
<li><strong>Tropenstürme häufiger</strong> — Kleine Schadensereignisse mit kurzem Mini-Spiel</li>
<li><strong>Waldbrände</strong> — Wenn zu viele Wälder + zu hohe Temperatur → ein Wald brennt ab</li>
<li><strong>Klima-Migration</strong> — Bevölkerung wandert zur nächsten Insel ab (negativer Trend)</li>
<li><strong>Kipppunkte</strong> — Ab bestimmten Schwellwerten unumkehrbare Verschlechterung</li>
</ul>
</div>
</section>
<!-- ====================================================== -->
<section id="offen">
<h2>8. Offene Punkte & nächste Schritte</h2>
<h3>Kurzfristig</h3>
<ul>
<li><strong>Phase B: Drag-and-Drop-Platzierung (Baueditor)</strong> — Voraussetzung für Phase C</li>
<li>2D-Renderer: Zeitleiste und Housing-Logik auf <code>landSurface(x)</code> prüfen (Häuser auf dem Keil, nicht auf dem alten groundY)</li>
<li>2D-Renderer: Strom-System aus 3D-Version übernehmen</li>
<li>Graph-Info-Buttons auch in die anderen HTML-Pages (<code>game.html</code>, <code>erdbeben.html</code>, <code>energiemix.html</code>) einbauen</li>
<li>Citizen-Events mit <code>infoKey</code> versehen (mehr Kontext für Kinder)</li>
</ul>
<h3>Mittelfristig</h3>
<ul>
<li><strong>Phase C: Wohnungsbau + Neuankömmlinge</strong> (siehe Karte oben)</li>
<li>Krisen-Mini-Spiele (Option D)</li>
<li>Trace-Test um Citizen-Events und Stromausfall erweitern</li>
<li>Strom-Tooltip ausführlich machen + Bilder/Diagramm</li>
</ul>
<h3>Langfristig</h3>
<ul>
<li>Login/Account-System mit Node + Express + SQLite (pausiert)</li>
<li>Lehrer-Dashboard mit Klassenverwaltung</li>
<li>Forschungs-Export von <code>game_runs</code> als CSV</li>
<li>Weitere Simulationen im selben Framework (Bevölkerungsdynamik, Raumplanung, Planetary Boundaries)</li>
</ul>
</section>
<footer>
GeoGraSim · Klimawächter Entwicklungs-Log ·
automatisch generiert aus Chat-Dialog mit Claude ·
letzte Aktualisierung: 2026-04-11
</footer>
</div>
</body>
</html>
+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)
+61
View File
@@ -0,0 +1,61 @@
# GeoGraSim — Music Registry
Zentrale Zuordnung der Hintergrund-Tracks aus dem Suno-Pool zu den Modulen.
**Regel:** Jeder Track gehört einem Modul. Keine Doppel-Nutzung — sonst
hat der Schüler beim Modulwechsel dasselbe Stück im Ohr.
**Quell-Pool:** `.humanInput/Background Music/` (lokal, nicht deployed)
**Ziel-Ordner:** `App/sims/<modul>/assets/music/`
## Claim-Prozess
1. Modul schickt Claim-Wunsch an Atlas-Inbox (`_inbox/zentrale/`).
2. Atlas prüft diese Registry — Doppel-Nutzung ausgeschlossen?
3. Atlas bestätigt in Modul-Inbox, trägt Track hier ein.
4. Modul kopiert die Datei aus Pool nach `App/sims/<modul>/assets/music/<kebab-case>.mp3`.
5. Atlas verschiebt die Quelldatei nach `.humanInput/Background Music/_claimed/`
(damit andere Module sie nicht auswählen).
## Aktuelle Zuordnungen
| Track (Original) | Stil | Zugewiesen an | Zielname | Datum |
|----------------------------|--------------------------|---------------|----------------------------|-------------|
| Piano Lobby.mp3 | Lounge-Klavier | **klima** | `piano-lobby.mp3` | 2026-04-18 |
| Fingertip Rain.mp3 | Ambient-Nature (Regen) | **klima** | `fingertip-rain.mp3` | 2026-04-18 |
| Limestone Lullaby.mp3 | Ruhig, wiegend | **klima** | `limestone-lullaby.mp3` | 2026-04-18 |
| Vibrocoffee Calm.mp3 | Chill / Lo-Fi | **klima** | `vibrocoffee-calm.mp3` | 2026-04-18 |
| Rising Pressure.mp3 (v1) | Drama/Tension (2:31) | **klima** | `rising-pressure-v1.mp3` | 2026-04-18 |
| Rising Pressure (1).mp3 (v2)| Drama/Tension (4:12) | **klima** | `rising-pressure-v2.mp3` | 2026-04-18 |
| Porcelain Rain.mp3 | Zart, Regen-Ambiente | **fluss** | `porcelain-rain.mp3` | 2026-04-18 |
## Freie Tracks (noch claimbar)
| Track (Original) | Stil | Kandidaten |
|----------------------------|--------------------------|------------------|
| Patagonia Stringmap.mp3 | Natur-Expedition | heli, regenwald |
## Vorläufige Stil-Slots pro Modul
| Modul | Lounge | Ambient/Nature | Ruhig | Chill | Drama/Tension |
|-----------|------------|--------------------|------------------|------------------|---------------------|
| klima | Piano Lobby| Fingertip Rain | Limestone Lullaby| Vibrocoffee Calm | Rising Pressure (A/B-Test)|
| heli | — | Patagonia Stringmap| — | — | — |
| fluss | — | **Porcelain Rain** | — | — | — |
| stadt | — | — | — | — | — |
| regenwald | — | — | — | — | — |
Drama/Tension wird bei Game-Loss / Extremwerten getriggert — nicht vom
Spieler wählbar, sondern automatisch angesteuert.
Der Pool wächst — Thomas generiert bei Bedarf neue Suno-Tracks.
## Spieler-Auswahl
Pro Modul soll im Header ein **Musik-Dropdown** angeboten werden:
- Stil-Auswahl (Lounge / Ambient / Ruhig / Chill)
- Play/Pause, Lautstärke, Mute
- Einstellung in localStorage (persistent pro Gerät)
Das Dropdown wird im Template-System als Standard-Komponente bereitgestellt
(`ggs-music-player`), damit jedes Modul es gleich einbauen kann.