Compare commits

..

1 Commits

Author SHA1 Message Date
Adminator 97a8a2d0a2 Initial commit 2026-07-07 23:57:04 +00:00
5817 changed files with 3 additions and 1472757 deletions
-482
View File
@@ -1,482 +0,0 @@
# Briefing · Wal-Modul „Die große Wanderung"
**Für:** Claude Fable 5 (externe Sim-Instanz)
**Auftrag-Datum:** 2026-06-14
**Auftraggeber:** Thomas (Plattform-Owner) + Atlas (Plattform-Instanz)
---
## 0. Worum es geht
Du baust ein neues GeoGraSim-Simulationsmodul für die Lernplattform **geograsim.at**. Sim-ID: **`wal`**. Titel: **„Die große Wanderung"**. Du folgst dem Buckelwal *Megaptera novaeangliae* auf seiner ~6.000 km Migration von Alaska nach Hawaii — als Mutter-Kuh, die in den hawaiianischen Brutgebieten ihr Kalb zur Welt bringen wird.
Zielgruppe: Sek I (1116 Jahre, AT/CH/DE/LI). Dauer ein Durchgang: ca. 35 min. Lehrpersonen setzen es ein in Fächern **Geografie und wirtschaftliche Bildung**, **Biologie / Naturwissenschaft**, **Politische Bildung** und im **Querschnitt BNE** (Bildung für Nachhaltige Entwicklung).
Die Plattform stellt: Wrapper (existiert: `App/pages/wal.php`), DB-Eintrag (existiert: `module_info`), Plattform-Header, Glossar-Tooltip-Library, Quick-Intro-Library, Live-Cockpit-Anbindung, Submit-Endpoint, Persistenz-Pattern, Lehrplan-Anbindung, Design-System.
**Pflicht-Lektüre vor Start:**
1. [`App/docs/sim-spec-2026-06-12.md`](../App/docs/sim-spec-2026-06-12.md) — aktuelle Plattform-Conventions (Window-Globals, Submit, Header-Standard)
2. [`App/docs/module-interface.md`](../App/docs/module-interface.md) — Sprach-Konventionen (Lernarbeit statt Spiel — **kritisch**), iPad-Pattern, Leichte Sprache, Persistenz-Pflicht
3. Diese Datei — Wal-Spezifika und Konzept
---
## 1. Ausgangsmaterial — Thomas' Skizzen
Zwei HTML-Files liegen in `c:\xampp\htdocs\geograsim\.humanInput\wal\` als **Konzept-Skizze**:
- **`wal-simulator-v2(3).html`** — die narrative Rahmensimulation mit Leaflet-Karte und Choice-Mechanik (4 Etappen, 11 Begegnungen, Energy/Health/Stress, Endet mit Geburt in Maui). **Das ist die Basis.**
- **`wal-frachtroute(4).html`** — ein 3D-Action-Minispiel, das die Containerschiff-Begegnung detailliert ausspielt. **Wir bauen das in 2D nach.**
Du darfst und sollst diese Files **als Inhaltsquelle plündern** — Texte, Fakten, Fact-Boxes, Stage-Definitionen sind didaktisch gut und fachlich verifiziert. Plattform-Integration und Welt-Varianten kommen NEU hinzu.
---
## 2. Konzept-Erweiterung — Welt-Varianten (Pflicht)
Statt einer einzigen Reise gibt es **drei Welt-Varianten** entlang derselben Pazifik-Route. Lehrperson kann eine vorgeben (`window.WAL_FORCED_ERA = 1850|1990|2026`), sonst wählt Schüler:in im Sim-Intro.
### Variante 1850 — Vor dem Schutz
- Walfänger-Stationen auf den Aleuten und in Lahaina (Hawaii). Harpunenboote als Antagonisten.
- Krillschwärme dicht, Heringe massenhaft. Wassertemperatur stabil.
- Kein Plastik, kein Sonar, kaum Containerschiffe (Dampfschiff-Frühphase).
- Population global: ~125.000 Buckelwale.
- Begegnungen statt Frachter/Plastik/Sonar: **Harpunenboot · Walfang-Station · Verlorene Walgruppen · Eismeer-Sturm**.
### Variante 1990 — Erholung beginnt
- Walfangmoratorium 4 Jahre alt (seit 1986). Population ~10.00015.000.
- Begegnungen mit anderen Buckelwalen seltener — „Einsamkeit" als didaktisches Element.
- Erste Containerschifffahrt, aber dünn.
- Marine-Sonar gibt's, Geisternetze ja, Plastik wenig.
- Erholungsstory erlebbar — andere Wale gehören zum „seltenen Glück".
### Variante 2026 — Heute
- Population ~80.000, fast erholt.
- Dichter Schiffsverkehr, Mikroplastik, Klimaerwärmung verschiebt Krill polwärts.
- Schutzgebiete + IMO-Routen helfen.
- = das `wal-simulator-v2(3).html` wie es jetzt ist (mit Plattform-Integration und 2D-Minispiel).
**Didaktischer Mehrwert:** Lehrperson lässt Klasse aufteilen — Gruppe A 1850, B 1990, C 2026. Vergleichen in der Reflexion. Sehen: **wir kommen aus einer schlimmen Zeit, wir hatten Erfolg mit Schutz**. BNE-Erfolgsstory ohne 2050-Spekulation.
### Sprache 1850
Darf dramatisch sein, aber Sek-I-tauglich. **Kein Splatter, keine Tier-Quälszenen.** Pattern:
> „Am Horizont, Schwarz auf Grau, ein Walfänger-Mast. Du hörst das Geräusch ihrer Ruder — schwächer als heutige Frachter, aber gezielt. Sie suchen dich."
Konsequenzen wie heute: Stats-Effekte + Fact-Box mit historischem Kontext. Kein Tod auf Bildschirm; Game-Over heißt „Verlorene Reise" wie in 2026 auch.
---
## 3. Technik-Vorgaben
### 3.1 Stack
- **Vanilla HTML/JS/CSS.** Kein Build-Step, kein React, kein TypeScript.
- **2D, nicht 3D.** Begründung: Tiefenachse ist die spannende Dimension (Tauchen unter Schiffen, Krill in der Tiefe) — die zeigt 2D klarer. iPad-Touch ist 2D natürlicher. Three.js-Bundle/WebGL-Abhängigkeiten entfallen. Flat-Scandinavian-Plattform-Ästhetik passt 2D besser.
- **Leaflet** ist OK für die Welt-Karte (siehe wal-simulator-v2 — verwendet das bereits).
- **Canvas 2D** für die Action-Minispiele (Schiffsquerung, Sonar-Ausweichen, evtl. Bubble-Net-Timing).
- **localStorage** für Autosave (Pflicht — siehe module-interface.md §7b).
### 3.2 Plattform-Header (Pflicht — Standard)
```html
<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">Die große Wanderung</span>
<span class="ggs-header-badge" id="era-badge">2026</span>
<div class="ggs-header-spacer"></div>
<div class="ggs-header-actions">
<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>
```
Stylesheet einbinden: `<link rel="stylesheet" href="/assets/css/design-system.css">`.
### 3.3 Plattform-Globals (was vom Wrapper kommt)
```js
window.WAL_BASE // '/sims/wal/' — Basispfad für deine Assets
window.WAL_SESSION_MODE // 'free' | 'teacher_started'
window.WAL_FORCED_LEVEL // 1|2|3 wenn teacher_started, sonst null
window.WAL_FORCED_ERA // 1850 | 1990 | 2026 | null
window.WAL_SESSION_ID // string oder null
window.WAL_API_BASE // '/php/api'
window.STUDENT_EASY // true wenn Leichte Sprache aktiv
```
**Verhalten:**
- Wenn `WAL_FORCED_ERA` gesetzt → Sim startet direkt in dieser Welt, kein Era-Picker.
- Wenn `null` → Era-Picker als erstes Screen-Element (3 Karten: 1850 / 1990 / 2026).
- Wenn `STUDENT_EASY === true` → vereinfachte Sprache überall (siehe module-interface.md §4b).
### 3.4 Plattform-Globals (was du setzen musst)
```js
// 1) Live-Snapshot fürs Lehrer-Cockpit (alle 4s wird das gepollt)
window.GGS_LIVE_STATE = function () {
if (!gameReady) return null;
return {
simId: 'wal',
era: 1850|1990|2026,
stage: 1|2|3|4, // aktuelle Etappe
stageName: 'Frederick Sound', // Anzeigename
day: 42, // Tage seit Aufbruch
energy: 75,
health: 90,
stress: 30,
hasCalf: false,
progressPct: 45, // 0-100 (Etappe + Index)
health_status: 'good'|'ok'|'struggle', // Cockpit-Status-Punkt
};
};
// 2) Tutorial-Replay-Hook (für -Header-Button)
window.GGS_TUTORIAL = {
simId: 'wal',
title: '🐋 Die große Wanderung',
replay: function () { /* deine startTutorial() */ },
};
```
### 3.5 Submit am Reise-Ende (Pflicht)
```js
fetch(window.WAL_API_BASE + '/progress.php', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
credentials: 'same-origin',
body: JSON.stringify({
sim_id: 'wal',
action: 'submit_assessment',
data: {
level: eraToLevel(era), // 1850=1, 1990=2, 2026=3
stars: calcStars(), // 1-5
score: calcScore(), // 0-100
duration_ms: (window.__GGS_LIVE__ && window.__GGS_LIVE__.activeMs) || 0,
completed: true,
results: {
era: 1850|1990|2026,
days_total: state.day,
outcome: 'arrival_with_calf'|'arrival_no_calf'|'starvation'|'injury'|'whaling',
energy_end: state.energy,
health_end: state.health,
stress_peak: state.stressPeak,
stages_completed: state.stage,
encounters_total: state.encountersDone,
choices_log: state.choicesLog, // pro Begegnung: {stage, event_id, choice_label}
facts_seen: state.factsRead, // wieviele Fakt-Boxen angezeigt
},
},
}),
});
```
**Wichtig:** `duration_ms` aus `window.__GGS_LIVE__.activeMs` lesen (NICHT eigene Wall-Clock). Sonst zählt Idle mit.
### 3.6 Glossar-Tooltip (in den Begegnungs-Texten verlinken)
Lib einbinden:
```html
<script src="/assets/js/glossar-tooltip.js" defer></script>
<script>
window.addEventListener('DOMContentLoaded', () => {
GlossarTooltip.init({apiBase:'/php/api', moduleId:'wal'});
});
</script>
```
In den Begegnungs-Texten verwendest du:
```html
<span class="ggs-g" data-glossar="bubble-net">Bubble-Net</span>
```
Atlas liefert die Begriffe nach an die Glossar-Instanz. Vorschlag-Liste in §6.
### 3.7 Quick-Intro NICHT verwenden
Wir wollen ein **vollwertiges Tutorial** mit 4-5 Schritten + Bildern (Welt-Variante erklären, Choice-Mechanik, Stats erklären, Minispiele ankündigen). Quick-Intro wäre zu dünn für diese Sim.
### 3.8 Persistenz (Pflicht)
`localStorage`-Key: `ggs-save-wal-{era}` (z.B. `ggs-save-wal-1850`).
- Speichern nach jeder Begegnung + bei Era-Switch.
- Beim Reload: lädt den aktuellen Stand. Reset-Button (🔄) löscht und startet neu (mit Bestätigung).
- Pro Era ein separater Save (Schüler:in kann zwischen Welten wechseln, ohne Stand zu verlieren — relevant für Vergleichs-Reflexion).
Siehe module-interface.md §7b für Vollbeispiel.
### 3.9 iPad-Pattern (Pflicht)
- Touch-Ziele 36-40 px (Header-Buttons sind das schon).
- Choice-Buttons mind. 48 px hoch.
- `font-size: 16px` für Texteingaben (sonst zoomt Safari).
- Canvas-Minispiele mit `touch-action: none`.
- Kein Hover-only — alles per Tap erreichbar.
---
## 4. Inhaltsstruktur (basierend auf Thomas' Vorlage)
### 4.1 Etappen (alle drei Welt-Varianten)
| Etappe | Name | Saison |
|---|---|---|
| 1 | Frederick Sound · Alaska | September |
| 2 | Offener Nordpazifik | Oktober |
| 3 | Subtropischer Übergang | November |
| 4 | Hawaiianische Gewässer | Dezember |
Pro Etappe 2-4 Begegnungen. Endet immer mit Maui + (in 1850 vielleicht abweichend wegen Walfangstation Lahaina) Geburt des Kalbs.
### 4.2 Begegnungs-Matrix nach Welt-Variante
Aus dem Originalkonzept übernehmen + ergänzen:
#### Etappe 1 (Frederick Sound)
- **1850:** Bubble-Net (mit großer Gruppe — Population groß) · Letzte Begegnung Sommer-Gruppe
- **1990:** Bubble-Net (mit *kleiner* Gruppe — Population dünn) · Aufbruch *allein* (Reflexion: „Wo sind die anderen?")
- **2026:** Bubble-Net wie heute · Letzte Begegnung wie heute (das aktuelle Skript)
#### Etappe 2 (Offener Nordpazifik)
- **1850:** **Walfänger-Brigg** (sich annähernde Walfänger statt Frachter) · **Eisberg-Treibhindernis** statt Geisternetz · Sturm · Orcas
- **1990:** **Frachtroute dünn** (1-2 Schiffe pro Tag, ausweichbar) · Geisternetze JA (Hochzeit der Treibnetz-Fischerei) · Sturm · Orcas
- **2026:** Frachtroute dicht (heute) · Geisternetz · Sturm · Orcas
#### Etappe 3 (Subtropischer Übergang)
- **1850:** **Wal-Pod-Begegnung** (große Gruppe — bewahrtes Phänomen) · Sturm-Nachläufer · Kuroshio-Ausläufer
- **1990:** Marine-Sonar (Kalter Krieg!) · Treibmüll-Anfänge (statt voller Müllstrudel) · Kuroshio
- **2026:** Marine-Sonar · Pazifischer Müllstrudel · Kuroshio (das aktuelle Skript)
#### Etappe 4 (Hawaiianische Gewässer)
- **1850:** **Walfang-Station Lahaina am Horizont** · Geburt im versteckten Kanal
- **1990:** Erste Brutgebiete vor Maui (mit Walbeobachtungsbooten als neues Phänomen) · Geburt
- **2026:** Erste Brutgebiete (mit etablierter Walbeobachtung + Schiffsverkehr) · Geburt
### 4.3 Action-Minispiel Frachtroute (2D)
Inspiration: `wal-frachtroute(4).html`**aber in 2D**.
**Mechanik:**
- Seitenansicht: Wasseroberfläche oben, Tiefe unten bis ~150 m.
- Wal-Mutter (große Silhouette) + Wal-Kalb (kleiner, folgt nach).
- Schiffe ziehen von rechts nach links durch den oberen Bereich. Tiefgang 12-15 m sichtbar.
- Player steuert vertikal (↑↓) und horizontal (←→ — leichte Strömung).
- 2 Atem-Bars (Mutter, Kalb) — Auftauchen füllt, Tauchen leert. Kalb leert schneller.
- Progress-Bar oben: Querung der Route (0→100 %).
- Sonnenstrahlen-Effekte zur Tiefe (Vol-Light-Style, einfache lineare Gradienten).
**Verlier-Bedingungen** (wie im Original): Kollision Mutter, Kollision Kalb, Mutter ertrinkt (Atem 0), Kalb ertrinkt.
**Win-Bedingung:** Querung 100 % erreichen.
Die Variante:
- **1850:** Ersetzt durch **Walfänger-Brigg-Begegnung** — kein Tauchspiel, Choice-basiert (sicher umgehen vs. nahe ran), KEIN Minispiel.
- **1990:** Mini-Action wie 2026, aber nur 1-2 Schiffe statt Dauer-Strom.
- **2026:** Voll-Action wie wal-frachtroute, aber 2D.
---
## 5. Cockpit-Sichtbarkeit & Benchmark — was Atlas brauchen wird
Du baust die Sim. Atlas verkabelt teacher.html + Benchmark.php sobald deine results-Felder definiert sind. **Liefere uns:**
### 5.1 LIVE_PRIMARY_FIELDS-Vorschlag
```js
'wal': [
{k:'health_status', label:'Status', align:'center', fmt: v => LIVE_VALUE_LABELS.health[v]},
{k:'era', label:'Welt', align:'center'},
{k:'stage', label:'Etappe'},
{k:'stageName', label:'Ort', align:'left'},
{k:'day', label:'Tag'},
{k:'progressPct', label:'Reise', fmt: v => _liveBar(v, 0, 100, 'mid')},
{k:'energy', label:'⚡ Energie', fmt: v => _liveBar(v, 0, 100, 'high')},
{k:'health', label:'❤️ Gesund.', fmt: v => _liveBar(v, 0, 100, 'high')},
{k:'stress', label:'😖 Stress', fmt: v => _liveBar(v, 0, 100, 'low')},
{k:'hasCalf', label:'🐳 Kalb', align:'center', fmt: v => v ? '✓' : '—'},
],
```
### 5.2 Benchmark-Formel-Vorschlag
```php
private static function scoreWal(array $r): ?int {
$era = (int)($r['era'] ?? 0);
$days = (int)($r['days_total'] ?? 0);
$outcome = $r['outcome'] ?? null;
$energy = (int)($r['energy_end'] ?? 0);
$health = (int)($r['health_end'] ?? 0);
$stressP = (int)($r['stress_peak'] ?? 0);
if (!$outcome) return null;
// Outcome-Basis
$base = match($outcome) {
'arrival_with_calf' => 70,
'arrival_no_calf' => 50,
'whaling' => 0,
'starvation' => 0,
'injury' => 0,
default => 0,
};
// Health- und Energy-Bonus (saubere Wahl)
$bonus = round($health * 0.12) + round($energy * 0.08);
// Stress-Malus (lange Belastung)
$malus = round($stressP * 0.05);
// Zeit-Malus (Zielreise ~90 Tage)
$timePenalty = max(0, ($days - 90)) * 0.3;
return max(0, min(100, (int)round($base + $bonus - $malus - $timePenalty)));
}
```
Begründung: Outcome dominiert (Kalb-Geburt = Hauptlernziel), Health/Energy als Wahlqualität, Stress-Malus für „durch-die-Hölle"-Routen.
---
## 6. Glossar-Begriffe — Atlas reicht das nach an die Glossar-Instanz
Bitte verwende in den Begegnungs-Texten Tooltips für diese Begriffe:
| Slug | Begriff | Wo verwendet |
|---|---|---|
| `bubble-net` | Bubble-Net-Feeding | Etappe 1 Begegnung 1 |
| `migration-orientierung` | Magnetfeld-Sinn / Orientierung | Etappe 2 Intro |
| `frachtroute` | Frachtroute (Pazifik-Hauptrouten) | Etappe 2 Frachter |
| `verkehrstrennungsgebiet` | IMO-Schifffahrtsroute | Etappe 2 Wins-Faktbox |
| `geisternetz` | Verloren gegangenes Fischereinetz | Etappe 2 Müll |
| `bycatch` | Beifang | Etappe 2 Geisternetz |
| `kuroshio-strom` | Kuroshio (warme Pazifikströmung) | Etappe 3 Kuroshio |
| `marine-sonar` | Militärisches Sonar | Etappe 3 Sonar |
| `mikroplastik` | Plastik-Anreicherung im Ozean | Etappe 3 Müll |
| `pazifischer-gyre` | Pazifischer Subtropen-Wirbel | Etappe 3 Müll |
| `walfang-moratorium` | IWC-Moratorium 1986 | Etappe 4 Faktbox + 1990-Intro |
| `iwc` | International Whaling Commission | wo Moratorium erwähnt |
| `walfaengerei-1850` | Walfangindustrie 19. Jh. | 1850-Etappen |
| `brutgebiet` | Hawaii Humpback Marine Sanctuary | Etappe 4 |
| `klimazone-subtropisch` | Subtropische Zone | Etappe 3 Intro |
| `wal-gesang` | Buckelwal-Gesang | Etappe 4 |
| `speck-blubber` | Speck als Energiereserve | Etappe 1 Intro |
| `echolot-tier` | Echo-Orientierung bei Walen | Etappe 2 Frachter Hintergrund |
| `bne` | Bildung für Nachhaltige Entwicklung | Endscreen |
| `lahaina` | Walfang-Station Maui 19. Jh. | 1850 Etappe 4 |
20 Begriffe. Atlas reicht das an die Glossar-Instanz weiter — du kannst die Slugs schon verwenden, Tooltip greift dann auf Fallback zurück bis die DB-Einträge da sind.
---
## 7. Lehrplan-Anker — Atlas reicht das nach an die Lehrplan-Instanz
Wir empfehlen pro Land 8-12 Anker. Vorerst nutzt du `module_kompetenz_map` mit folgenden bekannten Kompetenzen aus dem System:
- **AT GW Sek I:** Kompetenz 1.x (Klimazonen/Wassersysteme), 2.x (globale Stoffströme), 4.x (Belastungsgrenzen), 5.x (Mensch-Natur-Konflikte)
- **CH RZG Sek I:** RZG.3.x (Mensch-Natur-Systeme), RZG.4.x (globale Handelsketten)
- **DE Sek I:** Klimawandel, Welthandel, Globale Tier-Mensch-Konflikte
- **LI:** analog zu DE Berlin/Brandenburg-Pattern
Atlas liefert nach — du musst dazu nichts tun, außer im Modul-Header das 📚-Lehrplan-Link platzieren (das ist im Header-Standard bereits drin).
---
## 8. Dateien, die du anlegen sollst
```
App/sims/wal/
├── game.html ← Hauptdatei (du baust)
├── engine.js ← optional, Sim-Logik separat (empfohlen ab ~500 LoC)
├── assets/
│ ├── img/
│ │ ├── card-wal.png ← schon angefragt, kommt von Atlas
│ │ ├── era-1850.webp ← Onboarding/Era-Picker
│ │ ├── era-1990.webp
│ │ ├── era-2026.webp
│ │ ├── stage1-alaska.webp ← Etappen-Intro-Bilder
│ │ ├── stage2-nordpazifik.webp
│ │ ├── stage3-subtropisch.webp
│ │ └── stage4-hawaii.webp
│ └── audio/ ← optional, Walgesang (NOAA Public Domain)
│ └── humpback-song.mp3 ← falls du Audio-Element nutzt
```
**Bildstil:** Flat Scandinavian (siehe sim-spec-2026-06-12.md §6). DALL-E-Prompt-Block:
```
Flat scandinavian illustration, geometric shapes, soft warm color palette
(#1f4b37 forest, #4a7c4e moss, #e8c547 honey, #e8e4d8 sand background,
#b04a3e coral accent sparingly). No people, no text, no photo-realism.
Clean educational style for children 10-14, Sek I.
[hier deine Szene-Beschreibung]. Square 1024x1024.
```
WebP, max 200 KB pro Bild. Atlas hilft bei Bildgenerierung wenn du DALL-E-Briefings schickst.
---
## 9. Was Atlas am Ende übernimmt (du musst nicht)
1. `LIVE_PRIMARY_FIELDS['wal']` in [`App/teacher.html`](../App/teacher.html) einbauen (deine Vorlage aus §5.1)
2. `Benchmark::scoreWal()` in [`App/php/lib/Benchmark.php`](../App/php/lib/Benchmark.php) integrieren (deine Formel aus §5.2)
3. Glossar-Begriffe an Glossar-Instanz weiterreichen (deine Liste aus §6)
4. Lehrplan-Anker an Lehrplan-Instanz weiterreichen (Atlas-Vorschlag aus §7)
5. Playwright-Test in `.dontDeploy/playwright/tests/stufe1-smoke/`
6. Deploy
7. Status auf `aktiv` schalten nach Test-Welle
---
## 10. Done-Definition
Du gibst zurück:
- [ ] `App/sims/wal/game.html` (+ optional `engine.js`)
- [ ] Sim-eigene Assets in `App/sims/wal/assets/`
- [ ] Eine kurze README im Sim-Ordner: was du implementiert hast, was offen ist
- [ ] Aktualisierte LIVE_PRIMARY_FIELDS-Liste (falls deine results-Felder anders heißen)
- [ ] Aktualisierte Benchmark-Formel (falls deine results-Felder anders heißen)
- [ ] Aktualisierte Glossar-Begriff-Liste (falls du Begriffe ergänzt oder umbenennst)
Die Sim muss:
- [ ] Alle 3 Welt-Varianten spielbar liefern
- [ ] Bei `WAL_FORCED_ERA` direkt in dieser Welt starten
- [ ] Bei `WAL_FORCED_ERA=null` Era-Picker zeigen
- [ ] `GGS_LIVE_STATE` mit allen Feldern aus §3.4 liefern
- [ ] `GGS_TUTORIAL.replay()` registrieren
- [ ] Submit am Reise-Ende abgeben
- [ ] localStorage-Autosave pro Era
- [ ] iPad-funktional sein
- [ ] Sprache: NIEMALS „spielen/Spiel/Spieler". Immer „bearbeiten/Simulation/Lernende". Sek-I-Du-Form.
- [ ] Leichte-Sprache-Variante respektieren wenn `STUDENT_EASY=true`
---
## 11. Wenn du Fragen hast
Bei Plattform-Fragen: Atlas (Plattform-Instanz). Bei inhaltlich-didaktischen Fragen: Thomas. Bei Glossar oder Lehrplan: jeweilige Instanzen (siehe sim-spec-2026-06-12.md §14).
Die Plattform-Standards in sim-spec-2026-06-12.md sind Pflicht — Abweichungen bitte vorher abklären, nicht eigenmächtig „abkürzen". Wenn dir Conventions fehlen oder unklar sind, frag — wir ergänzen die Spec.
**Erfolg: ein didaktisch starkes, fachlich korrektes, iPad-funktionales, persistentes Wal-Migrations-Modul mit drei vergleichbaren Welt-Varianten, das in eine 35-Minuten-Schulstunde passt.**
Viel Erfolg!
— Atlas
-8
View File
@@ -1,8 +0,0 @@
{
"error": {
"message": "Billing hard limit has been reached.",
"type": "billing_limit_user_error",
"param": null,
"code": "billing_hard_limit_reached"
}
}
File diff suppressed because it is too large Load Diff
File diff suppressed because one or more lines are too long
@@ -1,430 +0,0 @@
<?php
// Generator für lehrplan-uebersicht.html
$j = json_decode(file_get_contents(__DIR__ . '/lehrplan-synthese-phase3.json'), true);
$s = json_decode(file_get_contents(__DIR__ . '/_phase3_stats.json'), true);
function e($x) { return htmlspecialchars($x, ENT_QUOTES, 'UTF-8'); }
$sims_meta = [
'busfahrt' => ['title' => 'Busfahrt', 'emoji' => 'BUS'],
'energiemanager' => ['title' => 'Energiemanager', 'emoji' => 'ENERG'],
'eu-werkstatt' => ['title' => 'EU-Werkstatt', 'emoji' => 'EU'],
'farmer' => ['title' => 'Farmer', 'emoji' => 'FARM'],
'fluss' => ['title' => 'Fluss', 'emoji' => 'FLUSS'],
'heli' => ['title' => 'Heli', 'emoji' => 'HELI'],
'klima' => ['title' => 'Klima', 'emoji' => 'KLIMA'],
'klima-3d' => ['title' => 'Klima 3D', 'emoji' => 'K3D'],
'logistik' => ['title' => 'Logistik', 'emoji' => 'LOG'],
'sonnensystem' => ['title' => 'Sonnensystem', 'emoji' => 'SOLAR'],
'weltkueche' => ['title' => 'Weltkueche', 'emoji' => 'KOCH'],
];
$active_sims = array_keys($sims_meta);
$countries = ['AT', 'CH', 'DE', 'LI'];
$country_labels = ['AT' => 'AT', 'CH' => 'CH (SG)', 'DE' => 'DE', 'LI' => 'LI'];
// Top-Anker pro Sim aus Synthese: PRO LAND EINER (max 3 = AT+CH+DE)
// Plus: Anker-Zaehlungen pro Sim x Land fuer die Coverage-Ampel
$top_per_sim = [];
$count_sim_country_new = []; // [sim][country] = anzahl
$count_sim_country_existing = []; // bestand aus DB (wird unten gefuellt)
foreach ($active_sims as $sim) {
$top_per_sim[$sim] = ['AT' => null, 'CH' => null, 'DE' => null];
$count_sim_country_new[$sim] = ['AT' => 0, 'CH' => 0, 'DE' => 0, 'LI' => 0];
$count_sim_country_existing[$sim] = ['AT' => 0, 'CH' => 0, 'DE' => 0, 'LI' => 0];
}
foreach ($j['anchors_neu'] as $a) {
foreach ($a['sims'] as $sim) {
if (!isset($top_per_sim[$sim])) continue;
$c = $a['country'];
if (isset($count_sim_country_new[$sim][$c])) {
$count_sim_country_new[$sim][$c]++;
}
// pro Land den ersten Anker als Top-Beispiel speichern
if (in_array($c, ['AT', 'CH', 'DE']) && $top_per_sim[$sim][$c] === null) {
$top_per_sim[$sim][$c] = [
'country' => $c,
'title' => $a['title'],
'reference' => $a['reference'],
'kompetenz' => $a['kompetenz_zuordnung'],
'neu' => true,
];
}
}
}
// Bestand aus DB
try {
require_once 'C:/xampp/htdocs/geograsim/App/php/config/db.php';
$db = getDB();
$stmt = $db->query("SELECT km.module_id, la.country, COUNT(DISTINCT la.id) AS n
FROM lehrplan_anchors la
JOIN kompetenz_modules km ON la.kompetenz_id = km.kompetenz_id
GROUP BY km.module_id, la.country");
foreach ($stmt as $r) {
if (isset($count_sim_country_existing[$r['module_id']][$r['country']])) {
$count_sim_country_existing[$r['module_id']][$r['country']] = (int)$r['n'];
}
}
} catch (Exception $e) { /* lokal not available, fallback 0 */ }
// Ampel-Funktion: Anker-Zahl -> Farbe + Status
// Annahme: pro Land+Sim ist ein guter Abdeckungsgrad >= 4 Anker, OK >= 2, duenn 1, leer 0
function coverage_status($total) {
if ($total >= 6) return ['gut', '🟢', '#4a7c4e', '#e3e9d6'];
if ($total >= 3) return ['ok', '🟡', '#a37e1a', '#fff7e0'];
if ($total >= 1) return ['duenn', '🟠', '#9c4d2e', '#fde0db'];
return ['leer', '🔴', '#9c2e2e', '#fbcfcf'];
}
// Lücken aus den 3 JSON-Files
$gaps = [
[
'thema' => 'Plantage / Monokultur (Begriff)',
'sim_abgedeckt' => 'JA: Farmer-Sim modelliert Cluster-Risiko bei Monokultur; weltkueche zeigt Plantage-Klimabilanz.',
'lehrplan' => 'AT: nicht woertlich. BU 4. Kl. AT spricht von "Charakteristika der konventionellen Landwirtschaft". DE: NRW IF6 + BY-Gym-Geo10-LB7 nennen "Plantagenwirtschaft" woertlich. CH: WAH/RZG.3.2 nennt "Plantage" als Produktionsform.',
'status' => 'teilweise abgedeckt — AT-Lehrplan-Luecke. DE+CH wortwoertlich.',
],
[
'thema' => 'Fair Trade / fairer Handel (Begriff)',
'sim_abgedeckt' => 'NEIN — kein Sim-Konzept dafuer. Sinngemaess: weltkueche Klimabilanz + Farmer Importpreise.',
'lehrplan' => 'Begriff in keinem der Lehrplaene woertlich (AT/CH/DE). Sinngemaess ueber Globalisierungsbereiche.',
'status' => 'Sim-Luecke — Vorschlag: Fair-Trade-Badges in weltkueche-Rezepten.',
],
[
'thema' => 'Klimazonen explizit (Koeppen-Geiger)',
'sim_abgedeckt' => 'JA: Farmer (Sahel-Cluster, Tropen), klima (Klimazonen-Karte), klima-3d.',
'lehrplan' => 'AT: Begriff "Klimazonen" nicht woertlich im GW Sek I. DE: NRW IF5 "Klimazonen der Erde" + BY-Rs-Geo7 "Klima-/Vegetationszonen". CH: RZG.1.2 "Landschaftszonen" + "Kalte/gemaessigte/Subtropen-/Tropenzone".',
'status' => 'AT-Luecke. DE+CH stark verankert. Sim deckt es ab.',
],
[
'thema' => 'EU-Institutionen (Kommission, Parlament, Ministerrat) namentlich',
'sim_abgedeckt' => 'JA: EU-Werkstatt thematisiert Buergerinitiative — Institutionsnamen jedoch implizit.',
'lehrplan' => 'AT: GW 4.2 nennt nur "vier Grundfreiheiten, Euro, Bildungskooperationen". GPB 4. Kl. spricht von EU als Wirtschafts-/Friedensprojekt. Keine Institutionsnamen woertlich. DE: NRW IF7 + BY-Gym-Geo10 thematisieren EU-Politik. CH: RZG.8.3 spricht nur abstrakt von "europaeischer Einigung" + Schweiz-Position.',
'status' => 'Plattform-weite Luecke — kein Lehrplan nennt Kommission/Parlament/Rat woertlich. Atlas-Empfehlung: EU-Werkstatt kann Institutionsnamen einfuehren als Plus.',
],
[
'thema' => 'Systemisches Denken explizit',
'sim_abgedeckt' => 'JA: Plattform-Kompetenz #46 systemisches-denken existiert; logistik + klima nutzen sie.',
'lehrplan' => 'AT: GW 4.3 "Wandel der Machtverhaeltnisse zwischen Staaten ... NGOs, Konzernen". DE: DGfG-F2 "Zusammenwirken von Geofaktoren ... als System darstellen"; NRW SK1 "Geofaktoren-Zusammenwirken". CH: keine eigene Kompetenz, implizit in RZG.3.x.',
'status' => 'DE explizit, AT sinngemaess, CH implizit.',
],
[
'thema' => 'Logistik / Disposition als LP-Anker',
'sim_abgedeckt' => 'JA: logistik-Sim Kern.',
'lehrplan' => 'AT: GW 2.2 + GW 3.3 (Import/Export). DE: NRW IF10 "Just-in-time-Produktion" + DGfG-F3 "Welthandel". CH: WAH.2.2 "globale Warenstroeme, Import/Export, Logistik" woertlich.',
'status' => 'Stark verankert. Plattform-Kompetenz #43 wirtschaft-logistikverstaendnis matcht direkt.',
],
[
'thema' => 'Welternaehrung & Disparitaeten',
'sim_abgedeckt' => 'JA: Weltkueche + Farmer.',
'lehrplan' => 'AT: EH 2. Kl. + UT 13 + GW 1.3. DE: NRW IF7 + BY-Gym-Geo10-LB2 + BY-Rs-Geo9. CH: WAH.4.5 + NMG.7.4 + RZG.2.2.',
'status' => 'In ALLEN drei Laendern explizit. Loest neue Plattform-Kompetenz #108 welternaehrung-konsum-disparitaeten aus.',
],
[
'thema' => 'Plantage / Monokultur als Sim-Mechanik',
'sim_abgedeckt' => 'JA: Farmer-Cluster-Risiko, Schaedlingsanfaelligkeit. Welternaehrung-Sim Rezepte.',
'lehrplan' => 'Siehe oben.',
'status' => 'Sim deckt es voll ab.',
],
];
ob_start();
?><!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Lehrplan-Coverage Phase 3 · GeoGraSim</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',system-ui,sans-serif;background:#f5f2eb;color:#2a2a2a;line-height:1.5;padding:24px;max-width:1400px;margin:0 auto}
h1{color:#1f4e5a;font-size:1.6rem;margin-bottom:4px}
.sub{font-size:.82rem;color:#8a8a8a;margin-bottom:18px}
h2{color:#1f4e5a;font-size:1.15rem;margin:28px 0 10px;padding-bottom:6px;border-bottom:2px solid #4a7c8a;display:flex;align-items:center;gap:8px}
h3{color:#4a7c8a;font-size:.98rem;margin:18px 0 8px}
table{width:100%;border-collapse:collapse;font-size:.84rem;background:#fff;border-radius:6px;overflow:hidden;margin-bottom:10px}
th,td{text-align:left;padding:7px 10px;border-bottom:1px solid #e0ddd4;vertical-align:top}
th{background:#1f4e5a;color:#fff;font-weight:600;font-size:.74rem;text-transform:uppercase;letter-spacing:.04em}
tr:hover{background:#fafaf5}
tr:last-child td{border-bottom:none}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
td.num .delta{color:#4a7c4e;font-size:.78em;margin-left:4px}
td.num .delta.zero{color:#bbb}
td.zero{color:#cfcfcf}
code{background:#f5f2eb;padding:2px 6px;border-radius:3px;font-family:'JetBrains Mono',Consolas,monospace;font-size:.85em}
a{color:#1f4e5a}
.badge{display:inline-block;font-size:.68rem;font-weight:700;padding:2px 7px;border-radius:9999px;margin-right:4px}
.b-new{background:#e3e9d6;color:#4a6b3f}
.b-existing{background:#d6e3e9;color:#1f4e5a}
.b-country-at{background:#fde0db;color:#9c4d2e}
.b-country-ch{background:#fff7e0;color:#8a6516}
.b-country-de{background:#d6e3e9;color:#1f4e5a}
.b-country-li{background:#e0ddd4;color:#666}
.top-nav{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:10px 14px;margin-bottom:18px;font-size:.86rem;display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.top-nav a{text-decoration:none;padding:5px 11px;border-radius:6px;color:#1f4e5a}
.top-nav a:hover{background:#f5f2eb}
.top-nav a.active{background:#1f4e5a;color:#fff}
.info-box{background:#fff7e0;border-left:4px solid #d2a24c;padding:12px 16px;margin:14px 0;border-radius:0 6px 6px 0;font-size:.88rem}
.stat-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-bottom:14px}
.stat-card{background:#fff;border-radius:8px;padding:12px 16px;border:1px solid #e0ddd4}
.stat-card .label{font-size:.72rem;text-transform:uppercase;color:#888;font-weight:700;letter-spacing:.04em}
.stat-card .value{font-size:1.8rem;font-weight:800;color:#1f4e5a;line-height:1.1;margin-top:2px}
.stat-card .delta{font-size:.85rem;color:#4a7c4e;font-weight:600}
.sim-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px;margin-top:14px}
.sim-card{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:14px 16px}
.sim-card h4{color:#1f4e5a;font-size:.98rem;margin-bottom:8px;display:flex;align-items:center;gap:8px}
.sim-card .counts{font-size:.78rem;color:#666;margin-bottom:10px}
.sim-card .counts b{color:#1f4e5a}
.sim-card ul{list-style:none;padding:0;font-size:.84rem}
.sim-card li{padding:6px 0;border-bottom:1px dotted #e0ddd4}
.sim-card li:last-child{border-bottom:none}
.gap-list .gap-item{background:#fff;border:1px solid #e0ddd4;border-left:4px solid #d2a24c;border-radius:0 6px 6px 0;padding:12px 16px;margin-bottom:10px}
.gap-item h4{color:#1f4e5a;font-size:.95rem;margin-bottom:6px}
.gap-item .gap-line{font-size:.84rem;margin-top:4px}
.gap-item .gap-line b{color:#1f4e5a}
.gap-item .status{display:inline-block;font-size:.72rem;font-weight:700;padding:3px 10px;border-radius:9999px;background:#fff7e0;color:#8a6516;margin-top:6px}
.gap-item .status.full{background:#e3e9d6;color:#4a6b3f}
.gap-item .status.partial{background:#fde0db;color:#9c4d2e}
.matrix-table th.col-sim,.matrix-table td.col-sim{background:#fafaf5;font-weight:600;color:#1f4e5a}
.matrix-table td.cell{text-align:center;font-variant-numeric:tabular-nums}
.matrix-table td.cell.zero{color:#cfcfcf}
.matrix-table td.cell .new{display:inline-block;color:#4a7c4e;font-weight:700;font-size:.78em;margin-left:3px}
details{background:#fff;border:1px solid #e0ddd4;border-radius:6px;margin-bottom:8px}
details summary{padding:10px 14px;cursor:pointer;font-weight:600;color:#1f4e5a;font-size:.92rem}
details[open] summary{border-bottom:1px solid #e0ddd4}
details > div{padding:0 14px 12px}
.note{font-size:.78rem;color:#888;font-style:italic;margin-top:6px}
</style>
</head>
<body>
<nav class="top-nav">
<strong>Entwurfswerkzeug</strong>
<a href="index.html">Uebersicht</a>
<a href="../entwurf.html">Entwurf</a>
<a href="../review.html">Review</a>
<a href="accounts.html">Accounts</a>
<a href="standards.html">Standards</a>
<a href="lehrplan-uebersicht.html" class="active">Lehrplan-Coverage</a>
<a href="../../App/admin-sitemap.html" target="_blank">Sitemap</a>
</nav>
<h1>Lehrplan-Coverage Phase 3</h1>
<p class="sub">Stand: 2026-06-08 · Synthese-Snapshot AT/CH/DE/LI · Quelle: <code>.dontDeploy/entwurfswerkzeug/lehrplan-synthese-phase3.json</code></p>
<div style="background:#fff;border-radius:8px;padding:14px 18px;margin:14px 0;border:1px solid #e0ddd4">
<h3 style="color:#1f4e5a;margin:0 0 8px;font-size:1rem">📖 Was du auf dieser Seite siehst — kurz erklärt</h3>
<ul style="font-size:.9rem;line-height:1.6;margin:0;padding-left:1.4em;color:#3a3a3a">
<li><b>Anker</b> = ein wörtlicher Verweis aus einem Schul-Lehrplan auf eines unserer Sim-Themen.
Beispiel: AT-Lehrplan GW Kompetenz 3.3 sagt wörtlich „Import/Export — Außenwirtschaft Österreichs". Das ist ein Anker für unsere Busfahrt/Logistik/Weltküche-Sims.
Jeder Anker hat Land · Fach · Klassenstufe · wörtliches Zitat · Quelle-URL.</li>
<li><b>Plattform-Kompetenz</b> = einer von 14 (mit der neuen 15) intern definierten Sammelbegriffen wie „Klimawandel", „Welthandel", „Kartenkompetenz". Jede Sim ist mehreren zugeordnet. Anker werden indirekt über die Plattform-Kompetenz mit der Sim verknüpft.</li>
<li><b>Coverage / Abdeckung</b> = wie viele Anker wir pro Sim und pro Land haben. Wir zeigen <b>keine Prozente</b>, weil es keine geschlossene Soll-Liste „Lehrplan = 100 Anker" gibt. Stattdessen <b>Ampel</b>:
<span style="background:#e3e9d6;color:#4a6b3f;padding:2px 8px;border-radius:9999px;font-weight:700;font-size:.8em">🟢 gut ≥ 6</span>
<span style="background:#fff7e0;color:#a37e1a;padding:2px 8px;border-radius:9999px;font-weight:700;font-size:.8em">🟡 ok 35</span>
<span style="background:#fde0db;color:#9c4d2e;padding:2px 8px;border-radius:9999px;font-weight:700;font-size:.8em">🟠 dünn 12</span>
<span style="background:#fbcfcf;color:#9c2e2e;padding:2px 8px;border-radius:9999px;font-weight:700;font-size:.8em">🔴 leer 0</span></li>
<li><b>Bestand vs. neu:</b> „Bestand" = was schon in der DB war. „Neu" = was Phase-3-Recherche zusätzlich vorschlägt (noch nicht in DB — muss erst per SQL-Migration übernommen werden).</li>
</ul>
</div>
<div class="info-box">
<b>Quellen:</b> Bestand-Zahlen aus DB (<code>lehrplan_anchors</code>, <?=count($s['komp_titles'])-1?> Plattform-Kompetenzen).
Neu-Zahlen aus Phase-2-Synthese: AT-RIS BGBl. II 1/2023 (BMBWF Sek I + VS), CH-LP21 (Sankt Gallen-Quelle <code>sg.lehrplan.ch</code>), DE-DGfG/NRW/Niedersachsen/Bayern (alles wörtlich aus PDFs extrahiert).
</div>
<h2>Gesamt-Statistik vor und nach Phase 3</h2>
<div class="stat-cards">
<div class="stat-card">
<div class="label">Anker AT (bestand &rarr; neu)</div>
<div class="value"><?=$s['bestand_per_country']['AT']?> &rarr; <?=$s['bestand_per_country']['AT']+($s['neu_per_country']['AT']??0)?></div>
<div class="delta">+<?=$s['neu_per_country']['AT']??0?> aus BGBl. II 1/2023</div>
</div>
<div class="stat-card">
<div class="label">Anker CH (bestand &rarr; neu)</div>
<div class="value"><?=$s['bestand_per_country']['CH']?> &rarr; <?=$s['bestand_per_country']['CH']+($s['neu_per_country']['CH']??0)?></div>
<div class="delta">+<?=$s['neu_per_country']['CH']??0?> aus LP21 (SG)</div>
</div>
<div class="stat-card">
<div class="label">Anker DE (bestand &rarr; neu)</div>
<div class="value"><?=$s['bestand_per_country']['DE']?> &rarr; <?=$s['bestand_per_country']['DE']+($s['neu_per_country']['DE']??0)?></div>
<div class="delta">+<?=$s['neu_per_country']['DE']??0?> DGfG/NRW/NI/BY</div>
</div>
<div class="stat-card">
<div class="label">Anker LI</div>
<div class="value"><?=$s['bestand_per_country']['LI']?> &rarr; <?=$s['bestand_per_country']['LI']?></div>
<div class="delta" style="color:#888">unveraendert</div>
</div>
<div class="stat-card">
<div class="label">Total Anker</div>
<div class="value"><?=array_sum($s['bestand_per_country'])?> &rarr; <?=array_sum($s['bestand_per_country'])+array_sum($s['neu_per_country'])?></div>
<div class="delta">+<?=array_sum($s['neu_per_country'])?> Anker</div>
</div>
<div class="stat-card">
<div class="label">Plattform-Kompetenzen</div>
<div class="value">14 &rarr; 15</div>
<div class="delta">+1 (welternaehrung-konsum-disparitaeten)</div>
</div>
</div>
<h2>Sim &times; Land Matrix</h2>
<p class="sub">Anker pro Sim und Land. Format: <code>bestand</code> mit <span style="color:#4a7c4e;font-weight:700">+neu</span>.</p>
<table class="matrix-table">
<thead>
<tr>
<th class="col-sim">Sim</th>
<?php foreach ($countries as $c): ?>
<th class="num"><?=e($country_labels[$c])?></th>
<?php endforeach; ?>
<th class="num">Sum bestand</th>
<th class="num">Sum neu</th>
</tr>
</thead>
<tbody>
<?php foreach ($active_sims as $sim):
$cells = $s['sim_land_matrix'][$sim];
$sum_b = 0; $sum_n = 0;
foreach ($countries as $c) { $sum_b += $cells[$c]['bestand']; $sum_n += $cells[$c]['neu']; }
?>
<tr>
<td class="col-sim"><?=e($sims_meta[$sim]['title'])?></td>
<?php foreach ($countries as $c): $b = $cells[$c]['bestand']; $n = $cells[$c]['neu']; ?>
<td class="cell <?=($b==0 && $n==0)?'zero':''?>"><?=$b?><?php if($n>0): ?><span class="new">+<?=$n?></span><?php endif; ?></td>
<?php endforeach; ?>
<td class="num"><?=$sum_b?></td>
<td class="num"><span class="delta">+<?=$sum_n?></span></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<h2>Plattform-Kompetenz &times; Land Matrix</h2>
<p class="sub">Anker pro Plattform-Kompetenz und Land.</p>
<table class="matrix-table">
<thead>
<tr>
<th class="col-sim">Kompetenz</th>
<?php foreach ($countries as $c): ?>
<th class="num"><?=e($country_labels[$c])?></th>
<?php endforeach; ?>
<th class="num">Sum bestand</th>
<th class="num">Sum neu</th>
</tr>
</thead>
<tbody>
<?php foreach ($s['komp_titles'] as $kt):
$kid = (int)$kt['id'];
if (!isset($s['komp_land_matrix'][$kid])) {
// neue Kompetenz 108
$s['komp_land_matrix'][$kid] = ['AT'=>['bestand'=>0,'neu'=>0],'CH'=>['bestand'=>0,'neu'=>0],'DE'=>['bestand'=>0,'neu'=>0],'LI'=>['bestand'=>0,'neu'=>0]];
// Neu-Zaehlung aus Synthese
foreach ($j['anchors_neu'] as $a) {
if ($a['kompetenz_zuordnung'] === $kt['key_slug']) {
$s['komp_land_matrix'][$kid][$a['country']]['neu']++;
}
}
}
$cells = $s['komp_land_matrix'][$kid];
$sum_b = 0; $sum_n = 0;
foreach ($countries as $c) { $sum_b += $cells[$c]['bestand']; $sum_n += $cells[$c]['neu']; }
?>
<tr>
<td class="col-sim"><?=e($kt['title'])?> <?php if($kid==108): ?><span class="badge b-new">NEU</span><?php endif; ?><br><span class="note"><code><?=e($kt['key_slug'])?></code></span></td>
<?php foreach ($countries as $c): $b = $cells[$c]['bestand']; $n = $cells[$c]['neu']; ?>
<td class="cell <?=($b==0 && $n==0)?'zero':''?>"><?=$b?><?php if($n>0): ?><span class="new">+<?=$n?></span><?php endif; ?></td>
<?php endforeach; ?>
<td class="num"><?=$sum_b?></td>
<td class="num"><span class="delta">+<?=$sum_n?></span></td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<h2>Pro Sim — Abdeckung mit Ampel-System</h2>
<p class="sub">Pro Sim und Land ein Beispiel-Anker (AT/CH/DE) — plus Ampel für die Gesamtzahl der Anker pro Land. <b>🟢 grün</b> ≥ 6 Anker (gut abgedeckt) · <b>🟡 gelb</b> 3-5 (ok) · <b>🟠 orange</b> 1-2 (dünn) · <b>🔴 rot</b> 0 (gar nicht).</p>
<div class="sim-grid">
<?php foreach ($active_sims as $sim):
$cells = $s['sim_land_matrix'][$sim];
$sum_b = 0; $sum_n = 0;
foreach ($countries as $c) { $sum_b += $cells[$c]['bestand']; $sum_n += $cells[$c]['neu']; }
?>
<div class="sim-card">
<h4><?=e($sims_meta[$sim]['title'])?></h4>
<div class="counts">bestand insgesamt: <b><?=$sum_b?></b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+<?=$sum_n?></b></div>
<?php // Ampel-Zeile pro Land mit Beispiel-Anker ?>
<?php foreach (['AT', 'CH', 'DE'] as $cc):
$total_for_country = $cells[$cc]['bestand'] + $cells[$cc]['neu'];
[$status, $emoji, $color, $bg] = coverage_status($total_for_country);
$example = $top_per_sim[$sim][$cc] ?? null;
?>
<div style="background:<?=$bg?>;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:<?=$color?>">
<span style="font-size:1.1em"><?=$emoji?></span>
<span><?=$cc?> — <?=$total_for_country?> Anker (<?=$status?>)</span>
<?php if ($cells[$cc]['neu'] > 0): ?><span style="margin-left:auto;color:#4a7c4e;font-weight:700">+<?=$cells[$cc]['neu']?> neu</span><?php endif; ?>
</div>
<?php if ($example): ?>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> <?=e($example['title'])?>
<div class="note" style="margin-top:2px"><?=e($example['reference'])?></div>
</div>
<?php elseif ($total_for_country == 0): ?>
<div style="font-size:.75rem;color:#666;margin-top:4px;font-style:italic">kein Anker — Lehrplan-Lücke oder Sim noch nicht zugeordnet</div>
<?php else: ?>
<div style="font-size:.75rem;color:#666;margin-top:4px;font-style:italic">Anker bereits in der DB (siehe /lehrplan-Page)</div>
<?php endif; ?>
</div>
<?php endforeach; ?>
</div>
<?php endforeach; ?>
</div>
<h2>Themen-Luecken und Sim-Abdeckung</h2>
<p class="sub">Lehrplan-Begriffe, die in Phase 1 oder 2 als "nicht woertlich abgedeckt" gemeldet wurden — mit Sim-Querverweis.</p>
<div class="gap-list">
<?php foreach ($gaps as $g): ?>
<div class="gap-item">
<h4><?=e($g['thema'])?></h4>
<div class="gap-line"><b>Sim-Abdeckung:</b> <?=e($g['sim_abgedeckt'])?></div>
<div class="gap-line"><b>Lehrplan-Verankerung:</b> <?=e($g['lehrplan'])?></div>
<div class="status <?=(strpos(strtolower($g['status']),'voll')!==false?'full':(strpos(strtolower($g['status']),'teil')!==false?'partial':''))?>"><?=e($g['status'])?></div>
</div>
<?php endforeach; ?>
</div>
<h2>Methodik und Quellen</h2>
<details>
<summary>Datenquellen, Validierungsstatus, Fall-Back-Hinweise</summary>
<div>
<h3>AT — BGBl. II 1/2023</h3>
<p>RIS Rechtsinformationssystem des Bundes. Direkter PDF-Download + pdftotext-Extraktion. Wortwoertliche Zitate. 31 neue Anker.</p>
<p class="note">Quick-Fixes: 9 Subject-Korrekturen (5x "Politische Bildung" -> "Geschichte und Politische Bildung — Querschnitt", 4x "Informatische Bildung" -> "Digitale Grundbildung"). Optional: 33 GW-Anker mit Subject "GW" -> "Geografie und wirtschaftliche Bildung".</p>
<h3>CH — Lehrplan 21 / Kanton St. Gallen</h3>
<p>Quelle: <code>sg.lehrplan.ch</code> (Live-Auftritt Kanton St. Gallen, bestaetigt 2026-06-08 via WebSearch). LP21-Texte national einheitlich.</p>
<p class="note">URL-Verifikation: WebFetch HTTP 403 (Bot-Block) — wie bei v-fe.lehrplan.ch und gr.lehrplan.ch. URL-Schema (Codes b|id|4 fuer Fachbereiche) identisch. Bei manueller Pruefung von Thomas: 1:1-Match zur Stamm-LP21-Struktur erwartet. 41 neue Anker.</p>
<h3>DE — DGfG / NRW / NI / BY</h3>
<p>4 Quellen:</p>
<ul style="padding-left:18px">
<li><b>DGfG Bildungsstandards 2020</b> (10. Aufl., VGDH-PDF): 11 Anker (10 verwertet, DGfG-M2 als Querschnitt weggelassen)</li>
<li><b>NRW Kernlehrplan G9 Erdkunde 2019</b>: 14 Anker</li>
<li><b>Niedersachsen Kerncurriculum Gymnasium Erdkunde</b>: 7 Anker</li>
<li><b>Bayern LehrplanPLUS (Gym 5/7/10 + RS 7/8/9)</b>: 15 Anker</li>
</ul>
<p class="note">Quick-Fix: 4 Anker mit DGfG-Tot-URL <code>geographie.de/publikationen/</code> auf <code>vgdh.de/wp-content/uploads/2023/08/Bildungsstandards_Geographie_2020_Web.pdf</code> aktualisiert.</p>
<h3>Neue Plattform-Kompetenz</h3>
<p><code>welternaehrung-konsum-disparitaeten</code> — konsolidiert die AT-Vorschlagskompetenz "ernaehrungs-und-konsumkompetenz" und die DE-Vorschlagskompetenz "welternaehrung-disparitaeten" zu einer Plattform-Kompetenz mit wortwoertlichen Belegen aus EH 2. Kl. AT, UT 13 AT, NRW IF7, BY-Gym-Geo10-LB2, BY-Rs-Geo9, WAH.2.2 CH, WAH.4.5 CH, NMG.7.4 CH.</p>
</div>
</details>
</body>
</html>
<?php
$html = ob_get_clean();
file_put_contents(__DIR__ . '/lehrplan-uebersicht.html', $html);
echo "HTML geschrieben: " . strlen($html) . " Bytes\n";
@@ -1,200 +0,0 @@
<?php
// Generator für die Phase-3-Migration. Liest lehrplan-synthese-phase3.json und schreibt SQL.
$j = json_decode(file_get_contents(__DIR__ . '/lehrplan-synthese-phase3.json'), true);
function sqlstr($s) {
if ($s === null) return 'NULL';
return "'" . str_replace(["\\", "'"], ["\\\\", "''"], $s) . "'";
}
$out = '';
$out .= "-- =================================================================\n";
$out .= "-- Lehrplan-Erweiterung Phase 3 — ENTWURF (NICHT auto-ausführen)\n";
$out .= "-- Erstellt: 2026-06-08 (Atlas)\n";
$out .= "-- Quelle: .dontDeploy/entwurfswerkzeug/lehrplan-synthese-phase3.json\n";
$out .= "--\n";
$out .= "-- Inhalt:\n";
$out .= "-- 1. Neue Plattform-Kompetenz welternaehrung-konsum-disparitaeten\n";
$out .= "-- 2. Quick-Fixes Phase 1 (4 DE-URLs + 9 AT-Subjects)\n";
$out .= "-- 3. Optional: plattformweites GW-Fach-Update (33 Anker)\n";
$out .= "-- 4. 118 neue Anker (AT 31 + CH 41 + DE 46)\n";
$out .= "-- 5. kompetenz_modules-Verknuepfungen (weltkueche + 3 sek.)\n";
$out .= "--\n";
$out .= "-- Idempotenz: alle INSERTs verwenden ON DUPLICATE KEY UPDATE oder INSERT IGNORE.\n";
$out .= "-- Mehrfach-Ausfuehrung veraendert die DB ab dem zweiten Lauf nicht.\n";
$out .= "--\n";
$out .= "-- ACHTUNG: Vor Punkt 4 muss EINMALIG ein UNIQUE-Index angelegt werden:\n";
$out .= "-- ALTER TABLE lehrplan_anchors\n";
$out .= "-- ADD UNIQUE KEY uniq_anchor_identity (country, reference(120), kompetenz_id);\n";
$out .= "-- Ohne diesen Index sind die folgenden Anker-INSERTs nicht idempotent.\n";
$out .= "-- =================================================================\n\n";
$out .= "START TRANSACTION;\n\n";
// ===== 1. Neue Plattform-Kompetenz =====
$out .= "-- -----------------------------------------------------------------\n";
$out .= "-- 1. Neue Plattform-Kompetenz: welternaehrung-konsum-disparitaeten\n";
$out .= "-- -----------------------------------------------------------------\n";
$k = $j['meta']['neu_konsolidierte_plattform_kompetenz'];
$out .= "INSERT INTO kompetenzen (key_slug, title, description, category, age_min, age_max, sort_order)\n";
$out .= "VALUES (\n";
$out .= " " . sqlstr($k['key_slug']) . ",\n";
$out .= " " . sqlstr($k['title']) . ",\n";
$out .= " " . sqlstr($k['description']) . ",\n";
$out .= " " . sqlstr($k['category']) . ",\n";
$out .= " " . (int)$k['age_min'] . ", " . (int)$k['age_max'] . ", 108\n";
$out .= ") ON DUPLICATE KEY UPDATE\n";
$out .= " title = VALUES(title),\n";
$out .= " description = VALUES(description),\n";
$out .= " category = VALUES(category),\n";
$out .= " age_min = VALUES(age_min),\n";
$out .= " age_max = VALUES(age_max);\n\n";
$out .= "-- Variable fuer spaetere Anker-INSERTs:\n";
$out .= "SET @welternaehrung_id := (SELECT id FROM kompetenzen WHERE key_slug = 'welternaehrung-konsum-disparitaeten');\n\n";
// ===== 2. Quick-Fixes =====
$out .= "-- -----------------------------------------------------------------\n";
$out .= "-- 2. Quick-Fixes aus Phase 1\n";
$out .= "-- -----------------------------------------------------------------\n";
$qf1 = $j['quick_fix_details']['url_dgfg_alt_zu_vgdh'];
$out .= "-- 2.1: 4 DE-DGfG-URLs auf VGDH-PDF korrigieren (Phase 1: url_dead)\n";
$ids = implode(',', $qf1['betroffene_ids']);
$out .= "UPDATE lehrplan_anchors\n";
$out .= " SET reference_url = " . sqlstr($qf1['neuer_url']) . "\n";
$out .= " WHERE id IN (" . $ids . ")\n";
$out .= " AND reference_url = " . sqlstr($qf1['alter_url']) . ";\n";
$out .= "-- Vorher pruefen: SELECT id, reference_url FROM lehrplan_anchors WHERE id IN (" . $ids . ");\n\n";
$qf2 = $j['quick_fix_details']['subject_politische_bildung'];
$out .= "-- 2.2: 5 AT-Anker Politische Bildung -> Querschnitt-Kennzeichnung\n";
$ids2 = implode(',', $qf2['betroffene_ids']);
$out .= "UPDATE lehrplan_anchors\n";
$out .= " SET subject = " . sqlstr($qf2['neuer_subject']) . "\n";
$out .= " WHERE id IN (" . $ids2 . ")\n";
$out .= " AND subject = 'Politische Bildung';\n\n";
$qf3 = $j['quick_fix_details']['subject_informatische_bildung'];
$out .= "-- 2.3: 4 AT-Anker Informatische Bildung -> Digitale Grundbildung\n";
$ids3 = implode(',', $qf3['betroffene_ids']);
$out .= "UPDATE lehrplan_anchors\n";
$out .= " SET subject = " . sqlstr($qf3['neuer_subject']) . "\n";
$out .= " WHERE id IN (" . $ids3 . ")\n";
$out .= " AND subject = 'Informatische Bildung';\n\n";
// ===== 3. Optionales GW-Update =====
$out .= "-- -----------------------------------------------------------------\n";
$out .= "-- 3. OPTIONAL: Plattformweites GW-Fach-Update (33 AT-Anker)\n";
$out .= "-- -----------------------------------------------------------------\n";
$out .= "-- Vorher-Vergleich (fuer Review):\n";
$out .= "-- SELECT COUNT(*) AS gw_count FROM lehrplan_anchors WHERE subject='GW' AND country='AT';\n";
$out .= "-- Erwartet: 33 (Stand 2026-06-08)\n";
$out .= "-- Idempotenz: nach erstem Lauf 0 Treffer, da WHERE subject=GW.\n";
$out .= "--\n";
$out .= "-- Auskommentiert — bei Bedarf manuell aktivieren:\n";
$out .= "-- UPDATE lehrplan_anchors\n";
$out .= "-- SET subject = 'Geografie und wirtschaftliche Bildung'\n";
$out .= "-- WHERE subject = 'GW' AND country = 'AT';\n";
$out .= "--\n";
$out .= "-- Nachher-Vergleich:\n";
$out .= "-- SELECT COUNT(*) AS gw_count_after FROM lehrplan_anchors WHERE subject='GW' AND country='AT';\n";
$out .= "-- Erwartet: 0\n";
$out .= "-- SELECT COUNT(*) AS gwb_count FROM lehrplan_anchors\n";
$out .= "-- WHERE subject='Geografie und wirtschaftliche Bildung' AND country='AT';\n";
$out .= "-- Erwartet: 33\n\n";
// ===== 4. Neue Anker =====
$out .= "-- -----------------------------------------------------------------\n";
$out .= "-- 4. Neue Lehrplan-Anker (118 Datensaetze: AT 31 + CH 41 + DE 46)\n";
$out .= "-- -----------------------------------------------------------------\n";
$out .= "-- Identitaets-Match: (country, reference, kompetenz_id).\n";
$out .= "-- Bei Re-Ausfuehrung wird der Datensatz aktualisiert (URL/Quote/Title).\n\n";
$komp_map = [
'klimawandel' => 1,
'naturgefahren-hochwasser' => 2,
'karten-navigation-alpen' => 3,
'stadtplanung-raum' => 4,
'raeumliche-orientierung-europa' => 41,
'kartenkompetenz-logistik' => 42,
'wirtschaft-logistikverstaendnis' => 43,
'planungs-entscheidungskompetenz' => 44,
'verkehrserziehung-sicherheit' => 45,
'systemisches-denken' => 46,
'energieversorgung-speicherung' => 57,
'erdmechanik-klimazonen' => 80,
'eu-politische-beteiligung' => 93,
'landwirtschaft-klimazonen' => 107,
];
$idx = 0;
$total = count($j['anchors_neu']);
foreach ($j['anchors_neu'] as $a) {
$idx++;
$slug = $a['kompetenz_zuordnung'];
if ($slug === 'welternaehrung-konsum-disparitaeten') {
$komp_expr = '@welternaehrung_id';
} else {
if (!isset($komp_map[$slug])) {
$out .= "-- WARN: unbekannter Kompetenz-Slug $slug fuer " . $a['_source'] . " — uebersprungen\n\n";
continue;
}
$komp_expr = (string)$komp_map[$slug];
}
$out .= "-- [" . $idx . "/" . $total . "] " . $a['_source'] . " -> " . $slug . "\n";
$out .= "INSERT INTO lehrplan_anchors\n";
$out .= " (kompetenz_id, country, anchor_type, region, school_type, grade, subject, title, reference, reference_url, quote, sort_order)\n";
$out .= "VALUES (\n";
$out .= " " . $komp_expr . ",\n";
$out .= " " . sqlstr($a['country']) . ",\n";
$out .= " " . sqlstr($a['anchor_type']) . ",\n";
$out .= " " . ($a['region'] === null ? 'NULL' : sqlstr($a['region'])) . ",\n";
$out .= " " . sqlstr($a['school_type']) . ",\n";
$out .= " " . sqlstr($a['grade']) . ",\n";
$out .= " " . sqlstr($a['subject']) . ",\n";
$out .= " " . sqlstr($a['title']) . ",\n";
$out .= " " . sqlstr($a['reference']) . ",\n";
$out .= " " . sqlstr($a['reference_url']) . ",\n";
$out .= " " . sqlstr($a['quote']) . ",\n";
$out .= " " . (int)$a['sort_order'] . "\n";
$out .= ") ON DUPLICATE KEY UPDATE\n";
$out .= " anchor_type = VALUES(anchor_type),\n";
$out .= " region = VALUES(region),\n";
$out .= " school_type = VALUES(school_type),\n";
$out .= " grade = VALUES(grade),\n";
$out .= " subject = VALUES(subject),\n";
$out .= " title = VALUES(title),\n";
$out .= " reference_url = VALUES(reference_url),\n";
$out .= " quote = VALUES(quote),\n";
$out .= " sort_order = VALUES(sort_order);\n\n";
}
// ===== 5. kompetenz_modules =====
$out .= "-- -----------------------------------------------------------------\n";
$out .= "-- 5. kompetenz_modules-Verknuepfungen\n";
$out .= "-- -----------------------------------------------------------------\n";
foreach ($j['kompetenz_modules_neu'] as $km) {
$slug = $km['kompetenz_id_oder_slug'];
if ($slug === 'welternaehrung-konsum-disparitaeten') {
$kid_expr = '@welternaehrung_id';
} else {
if (!isset($komp_map[$slug])) continue;
$kid_expr = (string)$komp_map[$slug];
}
$out .= "INSERT IGNORE INTO kompetenz_modules (kompetenz_id, module_id, level, strength)\n";
$out .= "VALUES (" . $kid_expr . ", " . sqlstr($km['module_id']) . ", " . (int)$km['level'] . ", " . sqlstr($km['strength']) . ");\n";
}
$out .= "\n";
$out .= "COMMIT;\n\n";
$out .= "-- =================================================================\n";
$out .= "-- Erwartete Statistik nach Migration:\n";
$out .= "-- SELECT country, COUNT(*) FROM lehrplan_anchors GROUP BY country;\n";
$out .= "-- AT 134 (103+31), CH 57 (16+41), DE 64 (18+46), LI 7. Total: 262.\n";
$out .= "-- SELECT COUNT(*) FROM kompetenzen;\n";
$out .= "-- Vorher 14 + 1 neu = 15.\n";
$out .= "-- =================================================================\n";
file_put_contents(__DIR__ . '/../../App/Don_t_Deploy/2026-06-08-lehrplan-erweiterung-phase3.sql', $out);
echo "SQL geschrieben: " . strlen($out) . " Bytes\n";
File diff suppressed because one or more lines are too long
-372
View File
@@ -1,372 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Test-Accounts · GeoGraSim</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',system-ui,sans-serif;background:#f5f2eb;color:#2a2a2a;line-height:1.5;padding:24px;max-width:1300px;margin:0 auto}
h1{color:#1f4e5a;font-size:1.5rem;margin-bottom:4px}
.sub{font-size:.82rem;color:#8a8a8a;margin-bottom:14px}
h2{color:#1f4e5a;font-size:1.1rem;margin:24px 0 8px;padding-bottom:4px;border-bottom:2px solid #4a7c8a;display:flex;align-items:center;gap:8px}
h3{color:#4a7c8a;font-size:.95rem;margin:14px 0 6px}
table{width:100%;border-collapse:collapse;font-size:.84rem;background:#fff;border-radius:6px;overflow:hidden;margin-bottom:8px}
th,td{text-align:left;padding:6px 10px;border-bottom:1px solid #e0ddd4;vertical-align:top}
th{background:#1f4e5a;color:#fff;font-weight:600;font-size:.74rem;text-transform:uppercase;letter-spacing:.04em}
tr:hover{background:#fafaf5}
tr:last-child td{border-bottom:none}
code{background:#f5f2eb;padding:2px 6px;border-radius:3px;font-family:'JetBrains Mono',Consolas,monospace;font-size:.85em}
a{color:#1f4e5a}
.pw{font-family:'JetBrains Mono',Consolas,monospace;font-weight:700;color:#9c4d2e}
.pw.empty{color:#bbb;font-weight:400;font-style:italic}
.badge{display:inline-block;font-size:.68rem;font-weight:700;padding:2px 7px;border-radius:9999px;margin-right:4px}
.b-local{background:#d6e3e9;color:#1f4e5a}
.b-prod{background:#fde0db;color:#9c4d2e}
.b-admin{background:#e8c547;color:#5a4416}
.b-school{background:#e3e9d6;color:#4a6b3f;font-weight:500}
.top-nav{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:10px 14px;margin-bottom:18px;font-size:.86rem;display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.top-nav a{text-decoration:none;padding:5px 11px;border-radius:6px;color:#1f4e5a}
.top-nav a:hover{background:#f5f2eb}
.top-nav a.active{background:#1f4e5a;color:#fff}
.grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;align-items:start}
.info-box{background:#fff7e0;border-left:4px solid #d2a24c;padding:12px 16px;margin:14px 0;border-radius:0 6px 6px 0;font-size:.88rem}
.stat-row{display:flex;gap:18px;font-size:.84rem;color:#666;margin-bottom:8px;flex-wrap:wrap}
.stat-row b{color:#1f4e5a}
.login-link{font-size:.74rem;color:#4a7c8a;text-decoration:none;background:#f5f2eb;padding:2px 6px;border-radius:4px}
.login-link:hover{background:#1f4e5a;color:#fff}
details{background:#fff;border:1px solid #e0ddd4;border-radius:6px;margin-bottom:8px}
details summary{padding:10px 14px;cursor:pointer;font-weight:600;color:#1f4e5a;font-size:.92rem}
details[open] summary{border-bottom:1px solid #e0ddd4}
details > div{padding:0 14px 12px}
@media (max-width:900px){.grid{grid-template-columns:1fr}}
</style>
</head>
<body>
<nav class="top-nav">
<strong>🛠 Entwurfswerkzeug</strong>
<a href="index.html">Übersicht</a>
<a href="../entwurf.html">Entwurf</a>
<a href="../review.html">Review</a>
<a href="accounts.html" class="active">🔑 Accounts</a>
<a href="standards.html">📐 Standards</a>
<a href="legacy/" style="color:#6b6448">📂 legacy/</a>
<a href="toDelete/" style="color:#9c4d2e">📂 toDelete/</a>
<a href="../../App/admin-sitemap.html" target="_blank">📊 Sitemap</a>
</nav>
<h1>🔑 Test-Accounts</h1>
<p class="sub">Schnellzugang für Test-Logins (Lehrer:innen + Schüler:innen) · Stand: 2026-06-08</p>
<!-- ⭐ ANGEHEFTET — Schroffi-Klasse ganz oben für sofortigen Zugriff -->
<div style="background:linear-gradient(135deg,#fde0db 0%,#fff7e0 100%);border:3px solid #c85c4a;border-radius:12px;padding:18px 22px;margin:14px 0 22px;box-shadow:0 4px 14px rgba(200,92,74,.18)">
<div style="display:flex;align-items:center;gap:8px;margin-bottom:10px">
<span style="font-size:1.6rem"></span>
<span style="font-size:1.1rem;font-weight:800;color:#9c4d2e">Schroffis Online-Testklasse</span>
<span style="font-size:.74rem;background:#c85c4a;color:#fff;padding:3px 10px;border-radius:9999px;font-weight:700;letter-spacing:.05em">PROD · DIE BRAUCHE ICH OFT</span>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:14px">
<div>
<div style="font-size:.72rem;text-transform:uppercase;color:#8a6516;font-weight:700;letter-spacing:.05em;margin-bottom:4px">Lehrer-Login</div>
<div style="font-family:'JetBrains Mono',Consolas,monospace;font-size:.95rem;font-weight:700;color:#9c4d2e;background:#fff;padding:8px 12px;border-radius:6px;border:1px solid #c85c4a">
schroffenegger@ph-vorarlberg.ac.at
</div>
<div style="font-size:.74rem;color:#8a6516;margin-top:3px">id 107 · intern <code>schroffenegger_359</code></div>
</div>
<div>
<div style="font-size:.72rem;text-transform:uppercase;color:#8a6516;font-weight:700;letter-spacing:.05em;margin-bottom:4px">Klassen-Code (Schüler-Login)</div>
<div style="font-family:'JetBrains Mono',Consolas,monospace;font-size:1.4rem;font-weight:800;color:#9c4d2e;background:#fff;padding:6px 14px;border-radius:6px;border:1px solid #c85c4a;letter-spacing:.1em;text-align:center">
LCVZHN
</div>
<div style="font-size:.74rem;color:#8a6516;margin-top:3px">„Meine Klasse" · 4 Schüler:innen</div>
</div>
</div>
<table style="margin-top:14px;background:#fff">
<thead><tr><th>Username</th><th>Passwort</th><th>Display</th><th>Letzter Login</th></tr></thead>
<tbody>
<tr><td><code style="font-size:.95rem;font-weight:700">Lena</code></td><td class="pw" style="font-size:.95rem">fnahc</td><td>Lenchen</td><td>2026-05-29 09:42</td></tr>
<tr><td><code style="font-size:.95rem;font-weight:700">Teresa</code></td><td class="pw" style="font-size:.95rem">fnahc</td><td>Tesa</td><td><i style="color:#888">nie</i></td></tr>
<tr><td><code style="font-size:.95rem;font-weight:700">bubi</code></td><td class="pw" style="font-size:.95rem">fnahc</td><td></td><td><i style="color:#888">nie</i></td></tr>
<tr><td><code style="font-size:.95rem;font-weight:700">Franz</code></td><td class="pw" style="font-size:.95rem">fnahc</td><td></td><td><i style="color:#888">nie</i></td></tr>
</tbody>
</table>
<div style="display:flex;gap:10px;flex-wrap:wrap;margin-top:10px">
<a href="https://geograsim.at/login" target="_blank" style="background:#c85c4a;color:#fff;text-decoration:none;border-radius:6px;padding:8px 14px;font-weight:700;font-size:.86rem">👩‍🏫 Lehrer-Login</a>
<a href="https://geograsim.at/login" target="_blank" style="background:#fff;color:#9c4d2e;text-decoration:none;border-radius:6px;padding:8px 14px;font-weight:700;font-size:.86rem;border:1.5px solid #c85c4a">🧑‍🎓 Schüler-Login (Code LCVZHN)</a>
<a href="https://geograsim.at/teacher" target="_blank" style="background:#fff;color:#9c4d2e;text-decoration:none;border-radius:6px;padding:8px 14px;font-weight:700;font-size:.86rem;border:1.5px solid #c85c4a">🔴 Live-Cockpit</a>
</div>
</div>
<div class="info-box">
<b>So funktioniert Schüler-Login:</b>
Schüler:innen melden sich mit <code>Klassen-Code</code> (z.B. <code>JAKOB1</code>) + Username + (Plaintext-)Passwort an.
Wenn das Passwort <span class="pw empty">NULL</span> ist, verwendet die Klasse <i>Anonymous-Pattern</i> — kein Passwort,
nur Klassen-Code + Username. (<code>students.is_anonymous=1</code>).
</div>
<!-- ================== LOKAL ================== -->
<h2><span class="badge b-local">LOKAL</span> XAMPP-Dev-DB</h2>
<div class="stat-row">
<span>👩‍🏫 <b>7</b> Lehrer:innen</span>
<span>🏫 <b>5</b> Klassen</span>
<span>🧑‍🎓 <b>16</b> Schüler:innen</span>
<span><a href="http://localhost/geograsim/App/login.html" target="_blank" class="login-link">→ Login-Seite</a></span>
</div>
<h3>Lehrer:innen — lokal</h3>
<table>
<thead><tr><th>id</th><th>Username</th><th>E-Mail</th><th>Display-Name</th><th>Schule</th><th>Login</th></tr></thead>
<tbody>
<tr><td>1</td><td><code>demo</code></td><td></td><td>Demo-Lehrkraft</td><td></td><td><a class="login-link" href="http://localhost/geograsim/App/login.html?user=demo" target="_blank"></a></td></tr>
<tr><td>2</td><td><code>test_928</code></td><td>test@schule.at</td><td>Test Lehrer</td><td>Test Schule</td><td></td></tr>
<tr><td>99</td><td><code>testlehrer</code></td><td>test@geograsim.at</td><td>Test-Lehrkraft</td><td>Testschule</td><td></td></tr>
<tr><td>100</td><td><code>neu_915</code></td><td>neu@schule.at</td><td>Neuer Lehrer</td><td>Schule X</td><td></td></tr>
<tr><td>101</td><td><code>lernapps</code></td><td>lernapps@oead.at</td><td>OeAD Lernapps</td><td>OeAD</td><td></td></tr>
<tr><td>102</td><td><code>jakob</code> <span class="badge b-school">AT</span></td><td>jakob@geograsim.at</td><td>Jakob</td><td></td><td></td></tr>
<tr><td>103</td><td><code>v2admin</code> <span class="badge b-admin">ADMIN</span></td><td>v2admin@local</td><td>V2 Admin</td><td>Lokale V2-Test-Schule</td><td></td></tr>
</tbody>
</table>
<h3>Klassen + Schüler:innen — lokal</h3>
<details open>
<summary>Klasse <code>JAKOB1</code> · „Jakob 1" · 3 Schüler:innen · Lehrer <code>jakob</code></summary>
<div>
<table>
<thead><tr><th>Username</th><th>Passwort</th><th>Display-Name</th></tr></thead>
<tbody>
<tr><td><code>Alexom</code></td><td class="pw">3322</td><td>Alexom</td></tr>
<tr><td><code>Berturam</code></td><td class="pw">7788</td><td>Berturam</td></tr>
<tr><td><code>Sussama</code></td><td class="pw">9991</td><td>Sussama</td></tr>
</tbody>
</table>
</div>
</details>
<details>
<summary>Klasse <code>TEST01</code> · „Test" · 3 Schüler:innen · Lehrer <code>testlehrer</code></summary>
<div>
<table>
<thead><tr><th>Username</th><th>Passwort</th><th>Display-Name</th></tr></thead>
<tbody>
<tr><td><code>anna</code></td><td class="pw empty">NULL (anonym)</td><td>Anna</td></tr>
<tr><td><code>ben</code></td><td class="pw empty">NULL</td><td>Ben</td></tr>
<tr><td><code>clara</code></td><td class="pw empty">NULL</td><td>Clara</td></tr>
</tbody>
</table>
</div>
</details>
<details>
<summary>Klasse <code>P9BNKR</code> · „2B" · 3 Schüler:innen · Lehrer <code>test_928</code></summary>
<div>
<table>
<thead><tr><th>Username</th><th>Passwort</th><th>Display-Name</th></tr></thead>
<tbody>
<tr><td><code>schueler01</code></td><td class="pw empty">NULL (anonym)</td><td>schueler01</td></tr>
<tr><td><code>schueler02</code></td><td class="pw empty">NULL</td><td>schueler02</td></tr>
<tr><td><code>schueler03</code></td><td class="pw empty">NULL</td><td>schueler03</td></tr>
</tbody>
</table>
</div>
</details>
<details>
<summary>Klasse <code>V2DEMO</code> · „V2-Demo 1A" · 7 Schüler:innen · Lehrer <code>v2admin</code></summary>
<div>
<table>
<thead><tr><th>Username</th><th>Passwort</th><th>Display-Name</th></tr></thead>
<tbody>
<tr><td><code>lina</code></td><td class="pw empty">NULL</td><td>Lina</td></tr>
<tr><td><code>max</code></td><td class="pw empty">NULL</td><td>Max</td></tr>
<tr><td><code>mia</code></td><td class="pw empty">NULL</td><td>Mia</td></tr>
<tr><td><code>moxo</code></td><td class="pw empty">NULL</td><td>Moxomilian Jackbiel</td></tr>
<tr><td><code>sofia</code></td><td class="pw empty">NULL</td><td>Sofia</td></tr>
<tr><td><code>tim</code></td><td class="pw empty">NULL</td><td>Tim</td></tr>
<tr><td><code>yusuf</code></td><td class="pw empty">NULL</td><td>Yusuf</td></tr>
</tbody>
</table>
</div>
</details>
<details>
<summary>Klasse <code>GEO1A</code> · „1A" · 0 Schüler:innen · Lehrer <code>demo</code></summary>
<div><p class="sub">Leere Demo-Klasse.</p></div>
</details>
<!-- ================== PROD ================== -->
<h2><span class="badge b-prod">PROD</span> geograsim.at</h2>
<div class="stat-row">
<span>👩‍🏫 <b>17</b> Lehrer:innen</span>
<span>🏫 <b>11</b> Klassen</span>
<span>🧑‍🎓 <b>~70</b> Schüler:innen</span>
<span><a href="https://geograsim.at/login" target="_blank" class="login-link">→ Prod-Login</a></span>
</div>
<!-- ⭐ Schroffi-Eigene Test-Klasse — prominent gehighlightet -->
<div style="background:#fff7e0;border:2px solid #d2a24c;border-radius:8px;padding:14px 18px;margin:14px 0">
<h3 style="color:#8a6516;margin:0 0 8px;font-size:1rem">⭐ Meine Online-Testklasse (Thomas Schroffenegger, PH Vorarlberg)</h3>
<table style="margin:0;background:transparent">
<tbody>
<tr><th style="background:transparent;color:#8a6516;width:130px">Lehrer-Login</th>
<td><code>schroffenegger@ph-vorarlberg.ac.at</code> · <span class="sub" style="color:#8a6516;font-size:.78rem">(intern: <code>schroffenegger_359</code> · id 107)</span></td></tr>
<tr><th style="background:transparent;color:#8a6516">Klassen-Code</th>
<td><code style="font-size:1.05rem;font-weight:700;color:#9c4d2e">LCVZHN</code> · „Meine Klasse"</td></tr>
<tr><th style="background:transparent;color:#8a6516">Schüler-Login</th>
<td>Username + Passwort <code class="pw">fnahc</code> für alle 4</td></tr>
</tbody>
</table>
<table style="margin-top:8px">
<thead><tr><th>Username</th><th>Passwort</th><th>Display</th><th>Letzter Login</th></tr></thead>
<tbody>
<tr><td><code>Lena</code></td><td class="pw">fnahc</td><td>Lenchen</td><td>2026-05-29 09:42</td></tr>
<tr><td><code>Teresa</code></td><td class="pw">fnahc</td><td>Tesa</td><td><i style="color:#888">nie</i></td></tr>
<tr><td><code>bubi</code></td><td class="pw">fnahc</td><td></td><td><i style="color:#888">nie</i></td></tr>
<tr><td><code>Franz</code></td><td class="pw">fnahc</td><td></td><td><i style="color:#888">nie</i></td></tr>
</tbody>
</table>
<p class="sub" style="margin-top:6px;color:#8a6516">
🔗 Schüler-Login-URL: <a href="https://geograsim.at/login" target="_blank">geograsim.at/login</a> → Klassen-Code <code>LCVZHN</code>
</p>
</div>
<h3>Lehrer:innen — Prod (Stand 2026-06-08)</h3>
<table>
<thead><tr><th>id</th><th>Username</th><th>E-Mail</th><th>Display-Name</th><th>Schule</th></tr></thead>
<tbody>
<tr><td>1</td><td><code>demo</code></td><td></td><td>Demo-Lehrkraft</td><td></td></tr>
<tr><td>2</td><td><code>demo_563</code></td><td>demo@test.at</td><td>Demo Lehrer</td><td>Demo Schule</td></tr>
<tr><td>99</td><td><code>testlehrer</code></td><td>test@geograsim.at</td><td>Test-Lehrkraft</td><td>Testschule</td></tr>
<tr><td>100</td><td><code>test2_502</code></td><td>test2@geograsim.at</td><td>Reg Test</td><td>Schule</td></tr>
<tr><td>101</td><td><code>oem_767</code></td><td>oem@gmx.at</td><td>Thomas Schroffenegger</td><td>MS Dornbirn</td></tr>
<tr><td>102</td><td><code>konzett_998</code></td><td>konzett@msls.edu.dornbirn.at</td><td>Meenu Konzett</td><td>MS Lustenauerstrasse, Dornbirn</td></tr>
<tr><td>103</td><td><code>lernapps</code></td><td>lernapps@oead.at</td><td>OeAD Lernapps</td><td>OeAD</td></tr>
<tr><td>104</td><td><code>schroffi_650</code></td><td>schroffi@gmx.at</td><td>Harald Emmerich</td><td>vsm</td></tr>
<tr><td>105</td><td><code>thomas.schroffenegger_485</code></td><td>thomas.schroffenegger@ph-vorarlberg.ac.at</td><td>Thomas Schroffenegger</td><td>PH Vorarlberg</td></tr>
<tr><td>106</td><td><code>jakob</code></td><td>jakob@geograsim.at</td><td>Jakob</td><td></td></tr>
<tr><td>107</td><td><code>schroffenegger_359</code></td><td>schroffenegger@ph-vorarlberg.ac.at</td><td>schroffenegger</td><td></td></tr>
<tr><td>108</td><td><code>qpv-e25-073_251</code></td><td>qpv-e25-073@oead.at</td><td>qpv-e25-073</td><td></td></tr>
<tr><td>109</td><td><code>olivia.kaesche_683</code></td><td>olivia.kaesche@ruetischule.ch</td><td>olivia.kaesche</td><td></td></tr>
<tr><td>110</td><td><code>helmut.pecher_215</code></td><td>helmut.pecher@kphvie.ac.at</td><td>Helmut Pecher</td><td>PVS Strebersdorf</td></tr>
</tbody>
</table>
<h3>Klassen + Schüler:innen — Prod</h3>
<details open>
<summary>Klasse <code>K9FQ7R</code> · „1A" · 25 Schüler:innen · Lehrer <code>lernapps</code> (OeAD)</summary>
<div>
<p class="sub">OeAD-Lernapps Test-Klasse mit 4-stelligen Plaintext-Passwörtern.</p>
<table>
<thead><tr><th>Username</th><th>PW</th><th>Username</th><th>PW</th><th>Username</th><th>PW</th><th>Username</th><th>PW</th><th>Username</th><th>PW</th></tr></thead>
<tbody>
<tr>
<td><code>LernApp01</code></td><td class="pw">6746</td>
<td><code>LernApp02</code></td><td class="pw">8199</td>
<td><code>LernApp03</code></td><td class="pw">3187</td>
<td><code>LernApp04</code></td><td class="pw">7391</td>
<td><code>LernApp05</code></td><td class="pw">9111</td>
</tr>
<tr>
<td><code>LernApp06</code></td><td class="pw">6052</td>
<td><code>LernApp07</code></td><td class="pw">6628</td>
<td><code>LernApp08</code></td><td class="pw">5070</td>
<td><code>LernApp09</code></td><td class="pw">9488</td>
<td><code>LernApp10</code></td><td class="pw">5079</td>
</tr>
<tr>
<td><code>LernApp11</code></td><td class="pw">9578</td>
<td><code>LernApp12</code></td><td class="pw">3053</td>
<td><code>LernApp13</code></td><td class="pw">8932</td>
<td><code>LernApp14</code></td><td class="pw">2570</td>
<td><code>LernApp15</code></td><td class="pw">4978</td>
</tr>
<tr>
<td><code>LernApp16</code></td><td class="pw">1761</td>
<td><code>LernApp17</code></td><td class="pw">6538</td>
<td><code>LernApp18</code></td><td class="pw">6298</td>
<td><code>LernApp19</code></td><td class="pw">8051</td>
<td><code>LernApp20</code></td><td class="pw">1178</td>
</tr>
<tr>
<td colspan="10" style="font-style:italic;color:#888;padding:8px">+ LernApp2125 (Passwörter via SSH abrufbar)</td>
</tr>
</tbody>
</table>
</div>
</details>
<details>
<summary>Klasse <code>VRGETF</code> · „Meine Klasse" · 25 Schüler:innen · Lehrer <code>thomas.schroffenegger_485</code> (PH Vorarlberg)</summary>
<div>
<p class="sub">25 Schüler <code>schueler01</code> bis <code>schueler25</code> — alle Passwörter <code>NULL</code> (anonym).</p>
</div>
</details>
<details>
<summary>Klasse <code>TEST01</code> · „Test" · 3 Schüler:innen · Lehrer <code>testlehrer</code></summary>
<div>
<table>
<thead><tr><th>Username</th><th>Passwort</th><th>Display</th></tr></thead>
<tbody>
<tr><td><code>anna</code></td><td class="pw empty">NULL (anonym)</td><td>Anna</td></tr>
<tr><td><code>ben</code></td><td class="pw empty">NULL</td><td>Ben</td></tr>
<tr><td><code>clara</code></td><td class="pw empty">NULL</td><td>Clara</td></tr>
</tbody>
</table>
</div>
</details>
<details>
<summary>Klasse <code>8MY62C</code> · „1a" · 3 Schüler:innen · Lehrer <code>oem_767</code> (MS Dornbirn)</summary>
<div>
<p class="sub"><code>schueler01</code> bis <code>schueler03</code> — alle NULL.</p>
</div>
</details>
<details>
<summary>Klasse <code>JAKOB1</code> · „Jakob 1" · 3 Schüler:innen · Lehrer <code>jakob</code></summary>
<div><p class="sub">Spiegel der lokalen Klasse (Alexom/Berturam/Sussama).</p></div>
</details>
<details>
<summary>Klasse <code>LCVZHN</code> · „Meine Klasse" · 4 Schüler:innen · Lehrer <code>schroffenegger_359</code> (PH Vorarlberg)</summary>
<div><p class="sub">Klein-Setup, schueler0104, alle NULL.</p></div>
</details>
<details>
<summary>Klasse <code>MLVJBU</code> · „Meine Klasse" · 5 Schüler:innen · Lehrer <code>qpv-e25-073_251</code> (OeAD)</summary>
<div><p class="sub">5 Schüler:innen, vermutlich anonym.</p></div>
</details>
<details>
<summary>Klassen ohne Schüler:innen</summary>
<div>
<table>
<thead><tr><th>Code</th><th>Klasse</th><th>Lehrer</th></tr></thead>
<tbody>
<tr><td><code>GEO1A</code></td><td>1A</td><td>demo</td></tr>
<tr><td><code>BY66A9</code></td><td>1b</td><td>konzett_998 (MS Lustenauerstrasse)</td></tr>
<tr><td><code>YTU7H9</code></td><td>Meine Klasse</td><td>olivia.kaesche_683 (Rütischule CH)</td></tr>
<tr><td><code>Z8PKJN</code></td><td>Meine Klasse</td><td>helmut.pecher_215 (PVS Strebersdorf)</td></tr>
</tbody>
</table>
</div>
</details>
<div class="info-box" style="margin-top:24px">
<b>🔄 Daten neu ziehen:</b><br>
<code>"c:/xampp/php/php.exe" -r "..."</code> für lokal (siehe Memory),
und <code>ssh -i ~/.ssh/openclaw root@85.215.155.82 'docker exec webstack-mysql sh -c ...'</code> für Prod.<br>
Datei wird beim nächsten Sweep automatisch durch Atlas aktualisiert — bei Fragen einfach
<i>Update accounts.html</i>" sagen.
</div>
<footer style="margin:24px 0;text-align:center;font-size:.75rem;color:#8a8a8a">
Liegt unter <code>.dontDeploy/entwurfswerkzeug/accounts.html</code> · wird nicht deployed.
</footer>
</body>
</html>
@@ -1,144 +0,0 @@
{"id":1137,"country":"AT","subject":"Bewegung und Sport","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Bewegung und Sport — Orientierungslauf, Wandern","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Bewegung und Sport","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Orientierungslauf und Wandern mit Karte und Kompass sind praktische Anwendungen der Kartenkompetenz und Teil des Bewegung-und-Sport-Lehrplans.","kompetenz_id":3}
{"id":1224,"country":"AT","subject":"Bewegung und Sport","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Bewegung und Sport — Tourenplanung, Wetterbeobachtung, Sicherheit am Berg","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Bewegung und Sport","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Im Bereich „Bewegung im Freien\" werden Tourenplanung, Wetterbeurteilung, Lawinen- und Wegekunde behandelt. Die Heli-Simulation macht greifbar, was passiert, wenn diese Vorbereitung versagt — und warum Bergrettung immer ein Team-Einsatz ist.","kompetenz_id":3}
{"id":1095,"country":"AT","subject":"Biologie und Umweltbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Biologie und Umweltbildung — Ökosysteme, Arten­sterben, Anthropozän","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Biologie und Umweltbildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Klima­wandel wird im Fach Biologie und Umweltbildung über Ökosysteme, Lebensräume, Artenvielfalt und den Schutz von Boden, Wasser, Luft und Wald sichtbar. Der Namenszusatz „Umweltbildung\" macht den Bezug seit 2023 explizit.","kompetenz_id":1}
{"id":1115,"country":"AT","subject":"Biologie und Umweltbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Biologie und Umweltbildung — Ökosystem Fluss und Aue","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Biologie und Umweltbildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Das Fach behandelt den Lebensraum Fluss, Auwälder, Renaturierung und die Rolle von Überschwemmungen im natürlichen Kreislauf. Ökologische Grundlagen ergänzen den GW-Blick auf Hochwasserschutz.","kompetenz_id":2}
{"id":1153,"country":"AT","subject":"Biologie und Umweltbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Biologie und Umweltbildung — Grünraum und Stadtklima","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Biologie und Umweltbildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Der Fachlehrplan Biologie und Umweltbildung behandelt den Lebensraum Stadt, Stadtklima, Begrünung und die Rolle von Grünflächen für Gesundheit und Biodiversität.","kompetenz_id":4}
{"id":1197,"country":"AT","subject":"Biologie und Umweltbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Biologie und Umweltbildung — Tag-Nacht-Rhythmus, Jahreszeiten und Lebewesen","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Biologie und Umweltbildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Jahreszeiten prägen Lebenszyklen von Pflanzen und Tieren (Vegetationszonen, Zugvögel, Winterruhe). Tag-Nacht-Rhythmus steuert circadiane Biologie. Die Simulation macht die astronomische Ursache für biologische Phänomene sichtbar.","kompetenz_id":80}
{"id":1218,"country":"AT","subject":"Biologie und Umweltbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Biologie und Umweltbildung — Pflanzen, Tiere, Ökosysteme, Bodenkunde","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Biologie und Umweltbildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Der Lebensraum Boden, Nährstoffkreisläufe, Photosynthese, tierische Produktion und Ökosystem-Dienstleistungen sind biologische Fundamente der Landwirtschaft. Die Simulation behandelt Nutzpflanzen (Weizen, Mais, Reis, Banane, Kaffee, Olive, Datteln) und Nutztiere (Rind, Schaf, Kamel, Rentier) im jeweiligen ökologischen Kontext.","kompetenz_id":107}
{"id":1096,"country":"AT","subject":"Chemie","school_type":"MS \/ AHS-U","grade":"3.4. Klasse","title":"Chemie — Treibhausgase, Verbrennung fossiler Brennstoffe","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Chemie","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die chemischen Grundlagen von CO₂, Methan und Verbrennungsprozessen werden im Chemieunterricht der 4. Klasse behandelt. Sie liefern die stoffliche Basis für das Verständnis des Treibhauseffekts.","kompetenz_id":1}
{"id":1219,"country":"AT","subject":"Chemie","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Chemie — Düngung, Bodenchemie, Photosynthese","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Chemie","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Stickstoff-Phosphor-Kalium-Düngung, Bodenchemie und der Stoff­wechsel der Photosynthese (CO₂ + H₂O → Zucker) sind chemische Grundlagen, die Erträge erklären. Die Simulation referenziert diese Konzepte über Eignungsstufen und Bodenmüdigkeit.","kompetenz_id":107}
{"id":1205,"country":"AT","subject":"Deutsch","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Deutsch — Texte verstehen, argumentieren, beschwerden formulieren","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Deutsch","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"EU-Petitionen und Bürgerinitiativen schriftlich formulieren, Gesetzes­texte erschließen, Positionen begründet vortragen — die Sprachkompetenzen aus dem Deutschunterricht sind die Grundlage für aktive politische Beteiligung.","kompetenz_id":93}
{"id":1099,"country":"AT","subject":"Geschichte und politische Bildung","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Geschichte und politische Bildung — Industrialisierung und Klimapolitik","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Geschichte und politische Bildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Der menschengemachte Klimawandel lässt sich historisch als Folge der Industrialisierung einordnen. Klimaschutz­politik (Pariser Abkommen, EU-Green-Deal) ist Gegenstand der politischen Bildung ab der 3. Klasse.","kompetenz_id":1}
{"id":1118,"country":"AT","subject":"Geschichte und politische Bildung","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Geschichte und politische Bildung — Hochwasser­ereignisse Österreichs","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Geschichte und politische Bildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die großen Hochwasser­ereignisse (1954, 2002, 2013, 2024) sind historische Wendepunkte der österreichischen Schutzpolitik. Geschichte liefert den Kontext für politische und gesellschaftliche Reaktionen.","kompetenz_id":2}
{"id":1136,"country":"AT","subject":"Geschichte und politische Bildung","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Geschichte und politische Bildung — historische Karten, Grenzen","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Geschichte und politische Bildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Historische Karten zeigen, wie sich Räume, Grenzen und Ortsbezeichnungen über die Zeit ändern. Der kritische Umgang mit Kartenquellen ist eine Kernkompetenz der historischen Bildung.","kompetenz_id":3}
{"id":1154,"country":"AT","subject":"Geschichte und politische Bildung","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Geschichte und politische Bildung — Urbanisierung und Stadtentwicklung","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Geschichte und politische Bildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die historische Entwicklung europäischer Städte — von der Industrialisierung bis zur suburbanen Zersiedelung — erklärt die heutigen Raumstrukturen und ist Teil des GSP-Lehrplans.","kompetenz_id":4}
{"id":1179,"country":"AT","subject":"Geschichte und politische Bildung","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Geschichte und politische Bildung — Europäische Integration","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Geschichte und politische Bildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die Entwicklung der Europäischen Union, Handelsgeschichte und die historische Rolle von Häfen und Handelswegen stehen im Fachlehrplan Geschichte und ergänzen die räumliche Orientierung.","kompetenz_id":41}
{"id":1180,"country":"AT","subject":"Geschichte und politische Bildung","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Geschichte und politische Bildung — Industrialisierung und Handelsnetze","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Geschichte und politische Bildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die historische Entwicklung von Handelsnetzen, Industrialisierung und Globalisierung ist Gegenstand des GSP-Unterrichts und liefert den zeitlichen Kontext für heutige Logistiksysteme.","kompetenz_id":43}
{"id":1196,"country":"AT","subject":"Geschichte und politische Bildung","school_type":"MS \/ AHS-U","grade":"3.4. Klasse","title":"Geschichte und politische Bildung — Heliozentrisches Weltbild","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Geschichte und politische Bildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Der Wechsel vom geozentrischen zum heliozentrischen Weltbild (Kopernikus, Galilei) ist ein Wendepunkt der Wissenschaftsgeschichte. Die Simulation zeigt das heliozentrische Modell anschaulich und liefert den anschaulichen Grund, warum dieser Schritt überhaupt nötig wurde.","kompetenz_id":80}
{"id":1204,"country":"AT","subject":"Geschichte und politische Bildung","school_type":"MS \/ AHS-U","grade":"3.4. Klasse","title":"Geschichte und politische Bildung — EU-Geschichte und Demokratie","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Geschichte und politische Bildung","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die Entwicklung der Europäischen Union (Montanunion, EWG, Maastricht, Lissabon), das Verhältnis von supranationaler und nationaler Demokratie sowie der Vergleich politischer Systeme sind Kernbestand des Fachlehrplans GSP.","kompetenz_id":93}
{"id":1113,"country":"AT","subject":"Gesundheitsförderung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 3 — Gesundheitsförderung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Katastrophenvorsorge und Verhaltensregeln bei Naturgefahren gehören zur Gesundheits­bildung. Die Kompetenz zum Selbstschutz und zur Gemeinschaftshilfe wird in diesem Querschnittsthema didaktisch adressiert.","kompetenz_id":2}
{"id":1222,"country":"AT","subject":"Gesundheitsförderung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 3 — Gesundheits­förderung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Erste Hilfe, Notfallkommunikation, das Verhalten am Berg (Wetterbeobachtung, Tourenplanung, Lawinengefahr) sind Bausteine der Gesundheitsbildung. Heli-Navigation macht den Ernstfall sichtbar — und damit die Bedeutung präventiver Sicherheit.","kompetenz_id":3}
{"id":1082,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"1. Klasse (Sek I)","title":"Grundlagen des Klimawandels — nachhaltige Ernährung","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.9 \/ 1.10","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Grundlegende Phänomene und Prozesse beschreiben, die für das Verständnis des Klimawandels und seiner gesellschaftlichen, wirtschaftlichen und ökologischen Folgen wichtig sind; den Einfluss des Klimawandels auf die Erzeugung von ausreichenden und gesunden Nahrungsmitteln an Fallbeispielen erörtern.","kompetenz_id":1}
{"id":1083,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"2. Klasse (Sek I)","title":"Nachhaltiger Umgang mit Energie und Ressourcen","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 2.1 \/ 2.3","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die Nutzung erneuerbarer und nicht erneuerbarer Energieträger vergleichen und aus den Blickwinkeln von Klimawandel und Nachhaltigkeit reflektieren; den verantwortungsvollen Umgang mit den natürlichen Ressourcen wie Wasser, Luft oder Boden erörtern.","kompetenz_id":1}
{"id":1084,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Mensch und Natursysteme — Belastungsgrenzen der Erde","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.2 \/ 4.3 \/ 4.10","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Folgen der Überschreitung von Belastungsgrenzen der Erde, des Klimawandels oder des Artensterbens auf das Leben und Wirtschaften erörtern; nachhaltige wirtschaftliche Aktivitäten in der globalisierten Welt vor dem Hintergrund von Klimawandel, Ressourcenknappheit, Flucht und Migration diskutieren.","kompetenz_id":1}
{"id":1104,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"1. Klasse (Sek I)","title":"Wechselwirkungen von Naturereignissen und Lebensqualität","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.11 \/ 1.12","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Wechselwirkungen von Naturereignissen, Lebensqualität und Wirtschaften der Menschen anhand von Fallbeispielen beschreiben und erörtern; unterschiedliche Betroffenheit von Menschen und Gesellschaften durch Naturgefahren bewerten und Möglichkeiten solidarischen Handelns erörtern.","kompetenz_id":2}
{"id":1105,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Belastungsgrenzen der Erde — Hochwasser im Anthropozän","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.1 \/ 4.2","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Ausmaß des menschlichen Einflusses auf Natursysteme an Beispielen wie Land- und Ressourcennutzung beschreiben; Folgen der Überschreitung von Belastungsgrenzen der Erde auf das Leben und Wirtschaften erörtern — Hochwasser als unmittelbare Folge veränderter Flächennutzung.","kompetenz_id":2}
{"id":1221,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"2.3. Klasse (Sek I)","title":"Bergrettung und Katastrophenschutz im alpinen Raum","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.11 \/ 1.12","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Wechselwirkungen von Naturereignissen, Lebensqualität und Wirtschaften der Menschen anhand von Fallbeispielen beschreiben und erörtern; unterschiedliche Betroffenheit von Menschen durch Naturgefahren bewerten und Möglichkeiten solidarischen Handelns erörtern. Lawinen, Steinschlag, Hochwasser und Sturm machen Bergrettung mit dem Hubschrauber zur Lebensader im alpinen Raum.","kompetenz_id":2}
{"id":1124,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"1. Klasse (Sek I)","title":"Orientierung auf Maßstabsebenen mit Geomedien","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.3 \/ 1.6","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Das persönliche Leben beginnend in der Wohn-\/Schulortgemeinde auf verschiedenen Maßstabsebenen mit Hilfe von Geomedien einordnen und darstellen; Fallbeispiele aus Zentren und Peripherien mit Geomedien lokalisieren.","kompetenz_id":3}
{"id":1125,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"3. Klasse (Sek I)","title":"Zentren und Peripherien Österreichs in Geomedien","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 3.15 \/ 3.16","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Zentren und Peripherien Österreichs abgrenzen, in Geomedien verorten und die Relativität jeder Abgrenzung erläutern; Gestaltung von zentralen und peripheren Lebensräumen mit Hilfe von originalen Begegnungen und Geomedien vergleichen.","kompetenz_id":3}
{"id":1142,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"3. Klasse (Sek I)","title":"Raumnutzung und Nutzungskonflikte in Österreich","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 3.15 \/ 3.16 \/ 3.17","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Zentren und Peripherien Österreichs abgrenzen; Gestaltung zentraler und peripherer Lebensräume vergleichen; mit (Geo-)Medien Raumnutzungen für Wohnen, Arbeit, Verkehr, Freizeitaktivitäten und Tourismus vergleichen sowie Lösungsansätze der Raumplanung bei Nutzungskonflikten erörtern.","kompetenz_id":4}
{"id":1143,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Städte und Ballungsräume in einer globalisierten Welt","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.7 \/ 4.8","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Verteilung der Bevölkerung und unterschiedliche Bevölkerungsdynamik aus globaler Perspektive analysieren; Entwicklung, Bedeutung und Verteilung von Städten, Ballungsräumen und Peripherien mit (Geo-)Medien beschreiben und vergleichen.","kompetenz_id":4}
{"id":1160,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Länder, Regionen und Staaten Europas einordnen (lg-orient-01 \/ 02 \/ 03)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.4","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Unterschiedliche Gliederungen, Wahrnehmungen und Darstellungen von Europa und der Europäischen Union in ihrer Vielfalt beschreiben, in (Geo-)Medien analysieren und dazu kritisch Stellung beziehen.","kompetenz_id":41}
{"id":1161,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"3.4. Klasse (Sek I)","title":"Häfen, Terminals und große Verkehrsachsen verorten (lg-orient-04)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 3.6 \/ 4.8","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Industrieregionen, Tourismusregionen, landwirtschaftlich geprägte Regionen … sowie Entwicklung, Bedeutung und Verteilung von Städten, Ballungsräumen und Peripherien mit (Geo-)Medien beschreiben und vergleichen.","kompetenz_id":41}
{"id":1209,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"1.2. Klasse (Sek I)","title":"Hauptstädte und Staaten Europas verorten","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.3 \/ 1.6","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Persönliches Leben auf verschiedenen Maßstabsebenen mit Hilfe von Geomedien einordnen und darstellen; weltweit ausgewählte Fallbeispiele aus Zentren und Peripherien lokalisieren. Die topografische Orientierung in Europa (Hauptstädte, Staaten, Flüsse) ist das Fundament für alle weiteren Europa-Themen.","kompetenz_id":41}
{"id":1162,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"1. Klasse (Sek I)","title":"Karten lesen, Lagebeziehungen erkennen (lg-karte-01 \/ 02)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.3 \/ 1.6","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Persönliches Leben auf verschiedenen Maßstabsebenen mit Hilfe von Geomedien einordnen und darstellen; Gemeinsamkeiten und Unterschiede im Zusammenhang mit Wohnen und Mobilität in weltweit ausgewählten Fallbeispielen mit Geomedien lokalisieren.","kompetenz_id":42}
{"id":1163,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"3. Klasse (Sek I)","title":"Distanzen, Verkehrsnetze und Suchstrategien auf Karten deuten (lg-karte-03 \/ 04)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 3.15 \/ 3.17","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Mit Hilfe von (Geo-)Medien die Raumnutzungen für Wohnen, Arbeit, Verkehr, Freizeitaktivitäten und Tourismus vergleichen sowie Lösungsansätze der Raumplanung bei Nutzungskonflikten erörtern.","kompetenz_id":42}
{"id":1210,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"2.3. Klasse (Sek I)","title":"Maßstab und Distanz — Entfernungen zwischen Städten schätzen","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.4 \/ 3.15","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Wesentliche Charakteristika der räumlichen Umwelt erheben, beschreiben und individuell bewerten; Zentren und Peripherien Österreichs (und Europas) abgrenzen, in Geomedien verorten. Distanzen in Kilometern grob abzuschätzen ist eine Grundkompetenz der Kartenarbeit — von Wien nach Paris sind ungefähr 1240 km Luftlinie.","kompetenz_id":42}
{"id":1164,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"3. Klasse (Sek I)","title":"Güterströme und außenwirtschaftliche Verflechtungen verstehen (lg-wirt-01)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 3.14","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Gründe, Bedeutung sowie ökonomische, gesellschaftliche und ökologische Folgen der außenwirtschaftlichen Verflechtungen (Import\/Export) Österreichs mit der EU und der restlichen Welt erläutern.","kompetenz_id":43}
{"id":1165,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"3. Klasse (Sek I)","title":"Kombinierte Verkehre (Bahn · Schiff · LKW) nachvollziehen (lg-wirt-02 \/ 03)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 3.6 \/ 3.13","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Industrieregionen, Tourismusregionen … charakterisieren; die wirtschaftliche Entwicklung Österreichs anhand von Kenngrößen (BIP, Beschäftigung, Außenhandel) beschreiben und persönliche, gesellschaftliche und ökologische Folgen diskutieren.","kompetenz_id":43}
{"id":1166,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"2. Klasse (Sek I)","title":"Zeit-Kosten-Zusammenhänge reflektieren (lg-wirt-04)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 2.6 \/ 2.7","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Reflektierte Entscheidungen bei der Nutzung von Bank-, Verkehrs- oder Handelsdienstleistungen treffen; Angebot und Nachfrage auf Märkten sowie deren Funktionen insbesondere für die Preisbildung charakterisieren.","kompetenz_id":43}
{"id":1167,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"2. Klasse (Sek I)","title":"Reihenfolge und Einsatz knapper Mittel planen (lg-plan-01 \/ 02)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 2.8","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Einfache Projektideen zur Erzeugung von Gütern oder zur Bereitstellung von Dienstleistungen unter Analyse von Angebot, Nachfrage, Ressourceneinsatz, Knappheit und Preisgestaltung entwickeln, umsetzen und Auswirkungen reflektieren.","kompetenz_id":44}
{"id":1168,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"2. Klasse (Sek I)","title":"Leerfahrten vermeiden, Ressourcen sparsam einsetzen (lg-plan-03 \/ 04)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 2.1 \/ 2.3","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die Nutzung erneuerbarer und nicht erneuerbarer Energieträger aus den Blickwinkeln von Klimawandel und Nachhaltigkeit reflektieren; den verantwortungsvollen Umgang mit natürlichen Ressourcen erörtern.","kompetenz_id":44}
{"id":1169,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"1. Klasse (Sek I)","title":"Einfluss von Wetter, Sperren und Störungen auf Verkehr erkennen (lg-verk-01)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.11","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Wechselwirkungen von Naturereignissen, Lebensqualität und Wirtschaften der Menschen anhand von Fallbeispielen beschreiben und erörtern.","kompetenz_id":45}
{"id":1170,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"3. Klasse (Sek I)","title":"Verkehr als komplexes System aus Infrastruktur und Entscheidungen verstehen (lg-verk-02 \/ 03)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 3.17","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Mit Hilfe von (Geo-)Medien die Raumnutzungen für Wohnen, Arbeit, Verkehr, Freizeitaktivitäten und Tourismus vergleichen sowie Lösungsansätze der Raumplanung bei Nutzungskonflikten erörtern.","kompetenz_id":45}
{"id":1171,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Einzelentscheidungen wirken auf das Gesamtsystem (lg-sys-01 \/ 02)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.6","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Chancen und Herausforderungen der europäischen Integration sowie die Notwendigkeit und Schwierigkeit von gemeinsamen Problemlösungen auf europäischer Ebene in einer globalisierten Welt erörtern.","kompetenz_id":46}
{"id":1172,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Globale Lieferketten auf Europa-Ebene herunterbrechen (lg-sys-03)","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.10","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Elemente, Anforderungen und Herausforderungen nachhaltiger wirtschaftlicher Aktivitäten und Beziehungen in der globalisierten Welt diskutieren, zB vor dem Hintergrund von Klimawandel, Ressourcenknappheit, Armut und Wohlstand, Flucht und Migration.","kompetenz_id":46}
{"id":1182,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"2. Klasse (Sek I)","title":"Erneuerbare Energieträger und Wasserkraft","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 2.1","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die Nutzung erneuerbarer und nicht erneuerbarer Energieträger vergleichen und aus den Blickwinkeln von Klimawandel und Nachhaltigkeit reflektieren. Wasserkraft ist Österreichs wichtigste erneuerbare Stromquelle — die Simulation macht das Prinzip der gespeicherten Höhenenergie erfahrbar.","kompetenz_id":57}
{"id":1183,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"3. Klasse (Sek I)","title":"Wasserkraft als Wirtschaftsstandort Österreichs","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 3.6 \/ 3.13","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Industrieregionen … charakterisieren und verorten; die wirtschaftliche Entwicklung Österreichs anhand von Kenngrößen beschreiben. Alpine Pumpspeicher (Kaprun, Malta, Kops II, Reißeck, Limberg) sind ein zentraler Standortfaktor und Exportgut der österreichischen Energiewirtschaft.","kompetenz_id":57}
{"id":1184,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Mensch-Umwelt-Beziehungen — Eingriff in den Naturraum","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.1 \/ 4.3 \/ 4.10","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Ausmaß des menschlichen Einflusses auf Natursysteme an Beispielen wie Land- und Ressourcennutzung beschreiben; eigene Ideen für nachhaltige Handlungen entwickeln. Stauseen verändern Flüsse, Lebensräume und Landschaften — die Simulation macht den Zielkonflikt zwischen Energieausbau und Naturraum-Schutz erlebbar.","kompetenz_id":57}
{"id":1206,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"2. Klasse (Sek I)","title":"Lastausgleich im Tagesverlauf — Strombedarf verstehen","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 2.1 \/ 2.6","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Reflektierte Entscheidungen bei der Nutzung von Verkehrs- oder Handelsdienstleistungen treffen, erneuerbare Energieträger aus Blickwinkeln von Klimawandel und Nachhaltigkeit reflektieren. Strombedarf schwankt zwischen Werktag und Wochenende, Morgen und Mittag — die Simulation macht diese Tagesprofile erlebbar.","kompetenz_id":57}
{"id":1190,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"1. Klasse (Sek I)","title":"Beleuchtungszonen der Erde — Wendekreise und Polarkreise","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.4 \/ 1.6","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Wesentliche Charakteristika der räumlichen Umwelt erheben, beschreiben und individuell bewerten; Geomedien zur Lokalisierung nutzen. Wendekreise (23,5° N\/S), Polarkreise (66,5° N\/S) und Klimazonen sind Folge der Erdachsneigung — die Simulation macht diesen Zusammenhang sichtbar.","kompetenz_id":80}
{"id":1191,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"2. Klasse (Sek I)","title":"Klima und Wetter im globalen System","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 2.1 \/ 2.3","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Natürliche Ressourcen, Lebensraum-Klima und globale Zusammenhänge im Spiegel der Erdmechanik einordnen. Mitternachtssonne und Polarnacht zeigen, wie Achsneigung das lokale Klima prägt.","kompetenz_id":80}
{"id":1198,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Werte und zentrale Themen der EU","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.5","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die Bedeutung gemeinsamer Werte wie Friedenserhaltung, Demokratie oder Freiheit begründen und zentrale Themen der EU wie die vier Grundfreiheiten (Waren, Personen, Kapital und Dienstleistungen), den Euro, Bildungskooperationen, Qualitätsstandards, Verbraucherschutz oder Regionalentwicklung im Hinblick auf das eigene Leben reflektieren.","kompetenz_id":93}
{"id":1199,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Chancen und Herausforderungen der EU-Integration","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.6","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Chancen und Herausforderungen der europäischen Integration sowie die Notwendigkeit und Schwierigkeit von gemeinsamen Problemlösungen auf europäischer Ebene in einer globalisierten Welt erörtern.","kompetenz_id":93}
{"id":1200,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"EU-Gliederungen und Darstellungen analysieren","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.4","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Unterschiedliche Gliederungen, Wahrnehmungen und Darstellungen von Europa und der Europäischen Union in ihrer Vielfalt beschreiben, in (Geo-)Medien analysieren und dazu kritisch Stellung beziehen.","kompetenz_id":93}
{"id":1213,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"1. Klasse (Sek I)","title":"Nachhaltige Ernährung — wo wächst was?","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 1.8 \/ 1.9","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Ausgehend von individuellen Ernährungsgewohnheiten (land-)wirtschaftliche Produktion, deren gesellschaftliche, wirtschaftliche und naturräumliche Bedingungen sowie deren Wandel an weltweit ausgewählten Fallbeispielen verorten und vergleichen; den Einfluss des Klimawandels auf die Erzeugung von ausreichenden und gesunden Nahrungsmitteln erörtern.","kompetenz_id":107}
{"id":1214,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"3. Klasse (Sek I)","title":"Landwirtschaftlich geprägte Regionen Österreichs und der Welt","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 3.6","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Industrieregionen, Tourismusregionen, landwirtschaftlich geprägte Regionen und Regionen mit anderen wirtschaftlichen Schwerpunkten charakterisieren und verorten. Die Simulation deckt Klimazonen weltweit (Tropen, Subtropen, gemäßigte Zonen, Polargebiete) ab und macht Anbaugrenzen erlebbar.","kompetenz_id":107}
{"id":1215,"country":"AT","subject":"GW","school_type":"MS \/ AHS-U","grade":"4. Klasse (Sek I)","title":"Anbaugrenzen, Belastungsgrenzen, globale Welternährung","reference":"BMBWF GW-Lehrplan Sek I 2023, Kompetenz 4.1 \/ 4.10","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Ausmaß des menschlichen Einflusses auf Natursysteme an Beispielen wie Land- und Ressourcennutzung beschreiben; Anforderungen nachhaltiger wirtschaftlicher Aktivitäten in der globalisierten Welt diskutieren — darunter Klimawandel-Folgen für die Welternährung (Verschiebung von Anbauzonen, Verlust fruchtbarer Böden).","kompetenz_id":107}
{"id":1131,"country":"AT","subject":"Informatische Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 4 — Informatische Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"GIS und digitale Geomedien (OpenStreetMap, Atlas-Software, Geocaching) sind Anwendungsbeispiele der Informatischen Bildung. Im GW-Lehrplan über die Kompetenzen 1.3, 1.6 und 3.15 direkt verankert.","kompetenz_id":3}
{"id":1174,"country":"AT","subject":"Informatische Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 4 — Informatische Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Digitale Kartendienste, GIS, Routenplanung und Geocaching sind Anwendungsbeispiele der Informatischen Bildung — im Logistik-Modul durchgehend im Einsatz.","kompetenz_id":42}
{"id":1187,"country":"AT","subject":"Informatische Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 4 — Informatische Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Lastausgleich, Prognosen und Steuerentscheidungen sind algorithmische Aufgaben. Smart Grids und Lastmanagement sind direkte Anwendungen der Informatischen Bildung — im Pumpspeicher-Modell als Steuerlogik erfahrbar.","kompetenz_id":57}
{"id":1193,"country":"AT","subject":"Informatische Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 4 — Informatische Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"3D-Visualisierungen, Modellbildung und Simulation von Himmelsmechanik sind anschauliche Anwendungen der Informatischen Bildung. Die Simulation macht abstrakte astronomische Modelle direkt erlebbar.","kompetenz_id":80}
{"id":1212,"country":"AT","subject":"Interkulturelle Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 5 — Interkulturelle Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Hauptstädte, Sprachen und kulturelle Eigenheiten der europäischen Nachbarländer kennen ist Grundlage interkultureller Verständigung. Die Info-Cards der Busfahrt-Simulation liefern jeweils 2-3 Fakten zur Stadt — Bevölkerung, Sprache, Besonderheiten.","kompetenz_id":41}
{"id":1098,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Mathematik — Größen, Daten, Prozent (fächerübergreifendes Rechnen)","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Klimadaten werden gemessen, verglichen und berechnet: ppm, °C, MW, kWh, t CO₂, Prozentanteile im Energiemix. Der Mathematik-Lehrplan liefert mit „Größen\" und „Daten\" die Werkzeuge, um diese Zahlen einzuordnen.","kompetenz_id":1}
{"id":1117,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Mathematik — Pegelstände, Statistik, Wahrscheinlichkeit","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Hochwasser­ereignisse werden mit Jahrhundert-Wahrscheinlichkeiten (HQ100), Pegelkurven und statistischen Datenreihen gemessen. Der Mathematik-Lehrplan liefert die nötigen Werkzeuge zur Dateninterpretation.","kompetenz_id":2}
{"id":1134,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Mathematik — Koordinatensystem, Maßstab, Winkel","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Das zweidimensionale Koordinatensystem, Maßstabs­umrechnung, Winkelberechnung und Flächen gehören zum Mathematik-Kernstoff und sind die Basis für Kartenarbeit und Navigation.","kompetenz_id":3}
{"id":1152,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Mathematik — Flächenberechnung, Bevölkerungsdichte, Diagramme","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Flächen in Hektar, Bevölkerungsdichte in Einwohner pro km², Diagramme zum Flächenverbrauch — Stadtplanung arbeitet durchgehend mit Größen und Daten, die im Mathematik-Unterricht geübt werden.","kompetenz_id":4}
{"id":1211,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Mathematik — Maßstab, Verhältnisse, Größenordnungen von Strecken","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Maßstabsumrechnung (1 cm auf der Karte = 100 km in der Wirklichkeit), Schätzgenauigkeit und Größenordnungen sind klassische Mathematik-Anwendungsfelder. Die Busfahrt-Simulation übt sie an konkreten europäischen Distanzen.","kompetenz_id":42}
{"id":1178,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Mathematik — Optimierung, Zeit, Kosten, Wege","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Reihenfolge-Probleme, Routen, Kapazitätsverteilung, Zeit-Kosten-Berechnungen: Logistik ist ein Anwendungsfeld kombinatorischer und arithmetischer Kompetenzen aus dem Mathematik-Unterricht.","kompetenz_id":44}
{"id":1181,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"3.4. Klasse","title":"Mathematik — Modellierung vernetzter Systeme","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Funktionen, Abhängigkeiten, Diagramme und Datenauswertung sind mathematische Werkzeuge, um Systemverhalten zu modellieren — Voraussetzung für die Analyse logistischer Gesamtsysteme.","kompetenz_id":46}
{"id":1189,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Mathematik — funktionale Zusammenhänge, Diagramme, Bilanzen","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"5-Tage-Bedarfskurven lesen, Füllstände in Prozent berechnen, Zuflüsse und Abflüsse bilanzieren — die Simulation übt das Lesen funktionaler Zusammenhänge und einfache Bilanzrechnungen direkt am Anwendungsfall.","kompetenz_id":57}
{"id":1195,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Mathematik — Skalen, Verhältnisse, Größenordnungen","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Verhältnisse (Sonne:Erde:Mond ≈ 109:1:0,27), Skalenwechsel (symbolisch ↔ realistische Größen ↔ realistische Distanzen), Winkel (23,5° Achsneigung, 5,1° Mondbahn-Neigung) — die Simulation übt mathematisches Skalendenken in einem konkreten Anwendungsfall.","kompetenz_id":80}
{"id":1220,"country":"AT","subject":"Mathematik","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Mathematik — Karten, Eignungsklassen, Erträge in Prozent","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Mathematik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Karten- und Maßstabsarbeit, prozentuale Erträge (S1=100%, S2=80%, S3=60%, N1=30%, N2=0%), Bilanzrechnungen und Risikoabwägung — die Simulation übt mathematische Grundkompetenzen am konkreten Anwendungsfall.","kompetenz_id":107}
{"id":1132,"country":"AT","subject":"Medienbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 6 — Medienbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Karten sind Medien: Maßstab, Generalisierung und Darstellungswahl prägen das Bild des Raums. Die reflektierte Nutzung von Karten ist ein klassisches Medienbildungs-Lernziel.","kompetenz_id":3}
{"id":1203,"country":"AT","subject":"Medienbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 6 — Medienbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Wer macht europäische Politik sichtbar? Wer beeinflusst sie? Lobbyismus, Transparenzregister und der Umgang mit Quellen sind Querschnittsthemen der Medienbildung — die EU-Werkstatt arbeitet mit echten Fällen und ermöglicht Quellenkritik.","kompetenz_id":93}
{"id":1097,"country":"AT","subject":"Physik","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Physik — Wärmestrahlung, Energieformen, Treibhauseffekt","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Physik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Der Treibhauseffekt ist physikalisch über Strahlung, Wärmetransport und Energiebilanzen erklärbar. Das Fach Physik liefert Einheiten wie Watt, Kilowatt und Kilowattstunde, die für das Verständnis von erneuerbaren Energien zentral sind.","kompetenz_id":1}
{"id":1116,"country":"AT","subject":"Physik","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Physik — Wasserdruck, Strömung und Energie","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Physik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Hochwasser wird physikalisch durch Strömungsgeschwindigkeit, Wasserdruck und Energieabgabe beschreibbar. Diese Grundlagen erklären, warum Dämme brechen oder warum Retentionsräume Spitzenabflüsse reduzieren.","kompetenz_id":2}
{"id":1135,"country":"AT","subject":"Physik","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Physik — Projektion, Lot, Erdrotation","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Physik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Kartenprojektionen, die Kugelgestalt der Erde und die Erdrotation sind physikalische Grundlagen der Gradnetz-Orientierung. Auch die Schwerkraft (Lotrichtung) ist für Höhenmessungen relevant.","kompetenz_id":3}
{"id":1225,"country":"AT","subject":"Physik","school_type":"MS \/ AHS-U","grade":"3.4. Klasse","title":"Physik — Auftrieb, Wind, Wetterphänomene","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Physik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Hubschrauber-Auftrieb, Wirkung von Aufwind und Fallwind in den Alpen, Höhenmesser, Druck und Temperatur — die physikalischen Grundlagen erklären, warum mancher Einsatz zu gefährlich ist und warum die Höhenstufen reale Konsequenzen haben.","kompetenz_id":3}
{"id":1188,"country":"AT","subject":"Physik","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Physik — Energieerhaltung, Höhenenergie, Wirkungsgrad","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Physik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Pumpspeicher illustrieren das Prinzip der Energieerhaltung wie kein zweites: potentielle Lageenergie wird in elektrische Energie umgewandelt und umgekehrt. Wirkungsgrade beim Pumpen und Turbinieren machen physikalische Verluste konkret.","kompetenz_id":57}
{"id":1207,"country":"AT","subject":"Physik","school_type":"MS \/ AHS-U","grade":"3.4. Klasse","title":"Physik — Leistung, Arbeit, Spitzenlast vs. Grundlast","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Physik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Die Unterscheidung von Leistung (Watt, Megawatt) und Arbeit (Wattstunde, Megawattstunde), Grundlast und Spitzenlast sowie das Konzept des Wirkungsgrads sind Kernstoff der Physik. Der Energiemanager lässt diese Größen in Echtzeit-Bilanzen sichtbar werden.","kompetenz_id":57}
{"id":1194,"country":"AT","subject":"Physik","school_type":"MS \/ AHS-U","grade":"2.4. Klasse","title":"Physik — Himmelsmechanik, Licht, Größenordnungen","reference":"BMBWF Lehrplan Sek I 2023, Fachlehrplan Physik","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Erdrotation und Erdumlauf, Lichtausbreitung mit endlicher Geschwindigkeit (8 Min Sonnenlicht zur Erde), Größenordnungen im Sonnensystem (Sonne ≈ 1,3 Mio Erdvolumen) sind Kernbestandteile des Physik-Lehrplans und werden in der Simulation direkt angeschaut.","kompetenz_id":80}
{"id":1093,"country":"AT","subject":"Politische Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 7 — Politische Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Politische Bildung umfasst u.a. Klimaschutzpolitik, internationale Abkommen und demokratische Entscheidungsprozesse. Im GW-Lehrplan u.a. in den Kompetenzen 3.9 (ökosoziale Marktwirtschaft) und 4.6 (gemeinsame Problemlösungen in der EU) sichtbar.","kompetenz_id":1}
{"id":1114,"country":"AT","subject":"Politische Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 7 — Politische Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Raumordnung, Hochwasserschutz und die Finanzierung von Schutzbauten sind politische Entscheidungen. Das Thema „unterschiedliche Betroffenheit\" (Kompetenz 1.12) ist eng mit demokratischer Teilhabe und Solidarität verbunden.","kompetenz_id":2}
{"id":1149,"country":"AT","subject":"Politische Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 7 — Politische Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Stadt­planung, Widmungsverfahren und demokratische Beteiligung (Bürger­initiativen, Gemeinderatsbeschlüsse) sind Kernthemen der Politischen Bildung. Direkt im GW-Lehrplan über Kompetenz 3.17 (Lösungs­ansätze bei Nutzungs­konflikten) verankert.","kompetenz_id":4}
{"id":1173,"country":"AT","subject":"Politische Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 7 — Politische Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Europa als politisches System (EU, Grundfreiheiten, Regionalentwicklung) ist Querschnittsauftrag der Politischen Bildung. Orientierungsaufbau stützt die politische Urteilsbildung.","kompetenz_id":41}
{"id":1201,"country":"AT","subject":"Politische Bildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 7 — Politische Bildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Demokratie verstehen und mitgestalten ist das Kernanliegen der politischen Bildung. Die EU-Werkstatt macht das ordentliche Gesetzgebungsverfahren, das Initiativmonopol der Kommission und die Hürden der Bürgerinitiative an konkreten Fällen erlebbar.","kompetenz_id":93}
{"id":1092,"country":"AT","subject":"Umweltbildung für nachhaltige Entwicklung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 11 — Umweltbildung für nachhaltige Entwicklung","reference":"BMBWF Lehrplan Sek I 2023, Allgemeiner Teil, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Umweltbildung für nachhaltige Entwicklung ist in allen Unterrichtsgegenständen der Sek I verbindlich verankert. Im GW-Lehrplan ist Klimawandel über die Kompetenzen 1.5, 1.10, 2.1, 2.3, 4.2 und 4.3 direkt an dieses Querschnittsthema gebunden.","kompetenz_id":1}
{"id":1112,"country":"AT","subject":"Umweltbildung für nachhaltige Entwicklung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 11 — Umweltbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Hochwasser, Bodennutzung und Ökosysteme verbinden sich in der Umweltbildung zum Verständnis nachhaltiger Raumnutzung. Im GW-Lehrplan verankert in Kompetenz 2.3 (natürliche Ressourcen) und 4.1\/4.3 (Natursysteme).","kompetenz_id":2}
{"id":1151,"country":"AT","subject":"Umweltbildung für nachhaltige Entwicklung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 11 — Umweltbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Verdichtung vs. Zersiedelung, Grünräume und Flächenverbrauch sind BNE-Fragen. Der GW-Lehrplan bindet diese über Kompetenz 4.10 (nachhaltige Aktivitäten) an das Querschnittsthema.","kompetenz_id":4}
{"id":1177,"country":"AT","subject":"Umweltbildung für nachhaltige Entwicklung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 11 — Umweltbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Das Zusammenspiel von Ressourcenknappheit, Verkehrswegen und globalen Wertschöpfungsketten — BNE-Perspektive auf Logistik.","kompetenz_id":46}
{"id":1185,"country":"AT","subject":"Umweltbildung für nachhaltige Entwicklung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 11 — Umweltbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Pumpspeicher als Schlüssel der Energiewende: Sie verschieben überschüssigen Wind- und Solarstrom in Zeiten höherer Nachfrage. BNE behandelt diese Technologien als Kernbeitrag zu klimaneutraler Stromversorgung.","kompetenz_id":57}
{"id":1192,"country":"AT","subject":"Umweltbildung für nachhaltige Entwicklung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 11 — Umweltbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Das Verstehen von Klimazonen und Erd-Sonne-System ist Voraussetzung dafür, Klimawandel und globale Naturphänomene überhaupt einordnen zu können — Querschnitts-Auftrag der Umweltbildung.","kompetenz_id":80}
{"id":1216,"country":"AT","subject":"Umweltbildung für nachhaltige Entwicklung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 11 — Umweltbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Bodennutzung, Monokultur, Bodenmüdigkeit, Wasserverbrauch und Klimawandelanpassung in der Landwirtschaft sind Kernfelder der BNE. Die Simulation arbeitet mit Köppen-Geiger-Klimazonen und FAO-Eignungsklassen (S1N2) — wissenschaftlich fundiert, didaktisch reduziert.","kompetenz_id":107}
{"id":1133,"country":"AT","subject":"Verkehrs- und Mobilitätsbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 12 — Verkehrs- und Mobilitätsbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Routenplanung, Öffentliche-Verkehrs-Netze und die Orientierung im Raum sind praktische Anwendungsfelder der Mobilitätsbildung. Karten sind dabei das zentrale Werkzeug.","kompetenz_id":3}
{"id":1223,"country":"AT","subject":"Verkehrs- und Mobilitätsbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 12 — Mobilitätsbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Luftverkehr als Sondermobilität (Rettung, Transport, Versorgung) und die Verzahnung mit bodengebundenem Verkehr (Krankenwagen, Tunnelrettung) sind Querschnitt der Mobilitätsbildung. Heli ist nicht „spielen mit Hubschrauber\", sondern arbeiten an einer realen Verkehrs- und Rettungsinfrastruktur.","kompetenz_id":3}
{"id":1150,"country":"AT","subject":"Verkehrs- und Mobilitätsbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 12 — Verkehrs- und Mobilitätsbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Wie sich Städte in Zukunft mit MIV, ÖPNV, Fuß- und Radverkehr verbinden, ist Querschnittsthema der Mobilitäts­bildung. Eng verknüpft mit den GW-Kompetenzen 3.6 (Standortfaktoren) und 3.17 (Raum­planung).","kompetenz_id":4}
{"id":1176,"country":"AT","subject":"Verkehrs- und Mobilitätsbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 12 — Verkehrs- und Mobilitätsbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Reflektierte Verkehrs- und Mobilitätsentscheidungen, Wetter- und Störungseinflüsse, Sicherheit im Verkehr — das Querschnittsthema deckt das Logistik-Modul exakt ab.","kompetenz_id":45}
{"id":1208,"country":"AT","subject":"Verkehrs- und Mobilitätsbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 12 — Energie und Mobilität","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Elektromobilität verschiebt Lastprofile in der Nacht (Laden) und am Tag (Schnelllader) — Mobilität und Stromnetz hängen direkt zusammen. Der Energiemanager macht diese Verzahnung sichtbar.","kompetenz_id":57}
{"id":1094,"country":"AT","subject":"Wirtschafts-, Finanz- und Verbraucher:innenbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 13 — Wirtschaftsbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Der Zusammenhang zwischen nachhaltigem Konsum, ökosozialer Marktwirtschaft und Klimawandel ist Querschnittsauftrag — im GW über die Kompetenzen zu Energieträgern (2.1), Preisbildung (3.8) und globaler Wirtschaft (4.10) verankert.","kompetenz_id":1}
{"id":1175,"country":"AT","subject":"Wirtschafts-, Finanz- und Verbraucher:innenbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 13 — Wirtschaftsbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Produktions- und Handelsentscheidungen, Preisbildung, Kosten-Nutzen-Abwägungen und reflektierter Konsum sind Pflichtbereich der Wirtschaftsbildung — zentral im Logistik-Modul.","kompetenz_id":43}
{"id":1186,"country":"AT","subject":"Wirtschafts-, Finanz- und Verbraucher:innenbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 13 — Wirtschaftsbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Effizienz, Wirkungsgrade, Reservehaltung und der Wert von Energie zu unterschiedlichen Tageszeiten sind Wirtschaftsthemen — die Simulation macht Kosten-Nutzen-Abwägungen am Pumpspeicher-Beispiel anschaulich.","kompetenz_id":57}
{"id":1202,"country":"AT","subject":"Wirtschafts-, Finanz- und Verbraucher:innenbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 13 — Wirtschaftsbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Verbraucherschutz, Binnenmarkt-Standards (USB-C, Roaming, DSGVO) und die ökonomische Dimension von EU-Gesetzen sind Pflichtbereich der Wirtschaftsbildung. Die EU-Werkstatt verbindet politische Beteiligung mit konkreten Verbraucher:innen-Themen.","kompetenz_id":93}
{"id":1217,"country":"AT","subject":"Wirtschafts-, Finanz- und Verbraucher:innenbildung","school_type":"MS \/ AHS-U","grade":"1.4. Klasse","title":"Übergreifendes Thema Nr. 13 — Wirtschaftsbildung","reference":"BMBWF Lehrplan Sek I 2023, Vierter Teil (Übergreifende Themen)","reference_url":"https:\/\/www.ris.bka.gv.at\/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850","quote":"Globale Lieferketten von Lebensmitteln, Importpreis-Mechanik (Reefer-Container, Welt-Häfen), CO₂-Fußabdruck der Ernährung — die Simulation macht den ökonomischen Aspekt der Landwirtschaft sichtbar, von der Anbauentscheidung bis zum Marktpreis.","kompetenz_id":107}
{"id":1100,"country":"CH","subject":"BNE — Natürliche Umwelt und Ressourcen","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Lehrplan 21 — BNE-Rahmen","reference":"Lehrplan 21, BNE (Bildung für Nachhaltige Entwicklung)","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=e%7C200%7C1","quote":"Klimawandel ist im Lehrplan 21 explizit als BNE-Thema verankert und verbindet RZG, NT, WAH und ERG fächerübergreifend.","kompetenz_id":1}
{"id":1119,"country":"CH","subject":"BNE — Natürliche Umwelt und Ressourcen","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Lehrplan 21 — BNE-Perspektive „Natürliche Umwelt und Ressourcen\"","reference":"Lehrplan 21, BNE-Rahmen (Bildung für Nachhaltige Entwicklung)","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=e%7C200%7C1","quote":"Die BNE-Rahmenperspektive bindet Hochwasser und Naturgefahren an Nachhaltigkeit, Raumnutzung und Risikokompetenz über Fachgrenzen hinweg.","kompetenz_id":2}
{"id":1155,"country":"CH","subject":"BNE — Wirtschaft und Konsum","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Lehrplan 21 — BNE-Perspektive „Wirtschaft und Konsum\"","reference":"Lehrplan 21, BNE-Rahmen","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=e%7C200%7C1","quote":"Stadtplanung ist im Lehrplan 21 als BNE-Querschnittsthema über „Wirtschaft und Konsum\" und „Natürliche Umwelt und Ressourcen\" angebunden.","kompetenz_id":4}
{"id":1157,"country":"CH","subject":"Ethik, Religionen, Gemeinschaft (ERG)","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Ethik, Religionen, Gemeinschaft — Zusammenleben in Städten","reference":"Lehrplan 21, Fachbereich ERG","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C8%7C4","quote":"Das Zusammenleben unterschiedlicher Gruppen in urbanen Räumen (Integration, Vielfalt, Solidarität) ist Gegenstand des ERG-Fachbereichs.","kompetenz_id":4}
{"id":1121,"country":"CH","subject":"Mathematik","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Mathematik — Daten, Funktionen, Wahrscheinlichkeit","reference":"Lehrplan 21, Fachbereich Mathematik","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C1%7C4","quote":"Mathematik deckt Datenauswertung (Pegel­kurven, Regenmengen, Jährlich­keiten) ab, die in der Risikobeurteilung von Hochwasser eingesetzt werden.","kompetenz_id":2}
{"id":1139,"country":"CH","subject":"Mathematik","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Mathematik — Koordinaten und Maßstab","reference":"Lehrplan 21, Fachbereich Mathematik","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C1%7C4","quote":"Koordinaten­systeme, Maßstabs­umrechnungen und Flächen­berechnungen sind Teil des Mathematik-Lehrplans und unterstützen die Arbeit mit topografischen Karten.","kompetenz_id":3}
{"id":1138,"country":"CH","subject":"Medien und Informatik (MI)","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Medien und Informatik — Digitale Karten und GIS","reference":"Lehrplan 21, Fachbereich Medien und Informatik","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C10%7C4","quote":"Der Fachbereich MI deckt digitale Kartendienste (OpenStreetMap, GIS-Tools) und den reflektierten Umgang mit geographischen Daten explizit ab.","kompetenz_id":3}
{"id":1101,"country":"CH","subject":"Natur und Technik (NT)","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Natur und Technik — Treibhauseffekt, Energie, Stoffkreisläufe","reference":"Lehrplan 21, Fachbereich Natur und Technik","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C7%7C4","quote":"Der Fachbereich NT liefert die naturwissenschaftliche Erklärung des Treibhauseffekts, der Energieformen und der Kohlenstoff­kreisläufe.","kompetenz_id":1}
{"id":1120,"country":"CH","subject":"Natur und Technik (NT)","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Natur und Technik — Wasser, Energie, Naturereignisse","reference":"Lehrplan 21, Fachbereich Natur und Technik","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C7%7C4","quote":"NT liefert die naturwissenschaftlichen Grundlagen zu Wasser, Energie und Klimasystem — und damit die Erklärungs­basis, warum Hochwasser entsteht und wie Schutzmaßnahmen physikalisch wirken.","kompetenz_id":2}
{"id":1107,"country":"CH","subject":"RZG","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"RZG.1.3 — Naturereignisse und deren Auswirkungen","reference":"Lehrplan 21, Fachbereich RZG","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Die Schülerinnen und Schüler können die Entstehung von Naturereignissen (u.a. Hochwasser) erklären und daraus Schutz- und Verhaltensregeln ableiten.","kompetenz_id":2}
{"id":1127,"country":"CH","subject":"RZG","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"RZG.2.1 — Mit Karten und Atlas arbeiten","reference":"Lehrplan 21, Fachbereich RZG","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Die Schülerinnen und Schüler können sich mithilfe von Karten und weiteren Medien räumlich orientieren und Informationen aus Karten zu Räumen entnehmen.","kompetenz_id":3}
{"id":1145,"country":"CH","subject":"RZG","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"RZG.4.2 — Räume gestalten und sich aneignen","reference":"Lehrplan 21, Fachbereich RZG","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Die Schülerinnen und Schüler können Raumnutzungskonflikte erkennen, planerische Entscheidungen nachvollziehen und eigene Gestaltungsideen für städtische Räume entwickeln.","kompetenz_id":4}
{"id":1087,"country":"CH","subject":"RZG (Räume, Zeiten, Gesellschaften)","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"RZG.3.2 — Natürliche und vom Menschen veränderte Systeme analysieren","reference":"Lehrplan 21, Fachbereich RZG","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Die Schülerinnen und Schüler können Auswirkungen des Klimawandels auf natürliche und menschliche Systeme erklären und mögliche Handlungsoptionen abwägen.","kompetenz_id":1}
{"id":1140,"country":"CH","subject":"Überfachliche Kompetenzen — Methodische","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Lehrplan 21 — Methodische Kompetenzen (Informationen nutzen)","reference":"Lehrplan 21, Überfachliche Kompetenzen","reference_url":"https:\/\/v-fe.lehrplan.ch\/","quote":"Das Arbeiten mit Karten, Atlas und digitalen Medien ist als methodische überfachliche Kompetenz im Lehrplan 21 verankert und wirkt fächerübergreifend.","kompetenz_id":3}
{"id":1102,"country":"CH","subject":"Wirtschaft, Arbeit, Haushalt (WAH)","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Wirtschaft, Arbeit, Haushalt — Energieverbrauch und Konsum","reference":"Lehrplan 21, Fachbereich WAH","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C12%7C4","quote":"WAH behandelt den persönlichen Energieverbrauch, das Konsumverhalten und die Entscheidungen privater Haushalte — eine zentrale Hebel­ebene im Klimaschutz.","kompetenz_id":1}
{"id":1156,"country":"CH","subject":"Wirtschaft, Arbeit, Haushalt (WAH)","school_type":"Sek I (Zyklus 3)","grade":"7.9. Schuljahr","title":"Wirtschaft, Arbeit, Haushalt — Flächenmarkt und Wohnen","reference":"Lehrplan 21, Fachbereich WAH","reference_url":"https:\/\/v-fe.lehrplan.ch\/index.php?code=b%7C12%7C4","quote":"Der Fachbereich WAH behandelt Wohnen, Haushalt und Konsum — und damit den wirtschaftlichen Aspekt der Stadt­planung und der Flächennutzung.","kompetenz_id":4}
{"id":1089,"country":"DE","subject":"Erdkunde","school_type":"Gymnasium \/ Realschule","grade":"Jg. 910","title":"Globale Klimaveränderungen — Ursachen und Folgen","reference":"Hessisches Kerncurriculum Sekundarstufe I — Erdkunde","reference_url":"https:\/\/kultus.hessen.de\/unterricht\/kerncurricula-und-lehrplaene\/kerncurricula\/sekundarstufe-i-kerncurricula","quote":"Die Lernenden analysieren Klimaveränderungen, ordnen anthropogene Einflussfaktoren ein und bewerten Maßnahmen zur Minderung und Anpassung auf lokaler und globaler Ebene.","kompetenz_id":1}
{"id":1090,"country":"DE","subject":"Erdkunde","school_type":"Gymnasium (Sek I)","grade":"Jg. 910","title":"Klimawandel und nachhaltige Entwicklung","reference":"Niedersächsisches Kerncurriculum Gymnasium Sek I — Erdkunde","reference_url":"https:\/\/cuvo.nibis.de\/cuvo.php?p=download&upload=61","quote":"Die Schülerinnen und Schüler erörtern Ursachen und Folgen des Klimawandels und beurteilen Handlungsoptionen im Rahmen einer Bildung für nachhaltige Entwicklung (BNE).","kompetenz_id":1}
{"id":1109,"country":"DE","subject":"Erdkunde","school_type":"Gymnasium \/ Realschule plus","grade":"Jg. 710","title":"Leben mit Naturgefahren — Hochwasser an Rhein und Mosel","reference":"Lehrplan Gesellschaftswissenschaften Sek I (2021), Rheinland-Pfalz","reference_url":"https:\/\/static.bildung-rp.de\/lehrplaene\/gesellschaftswissenschaften\/Ek_G_Sk_Sek_I__LP_2021_.pdf","quote":"Die Lernenden beschreiben Ursachen und Verlauf von Hochwasserereignissen an grossen mitteleuropäischen Flüssen und bewerten Schutzstrategien.","kompetenz_id":2}
{"id":1111,"country":"DE","subject":"Erdkunde","school_type":"Gymnasium \/ Realschule","grade":"Jg. 78","title":"Naturräumliche Prozesse — Extremwetter und Hochwasser","reference":"Hessisches Kerncurriculum Sekundarstufe I — Erdkunde","reference_url":"https:\/\/kultus.hessen.de\/unterricht\/kerncurricula-und-lehrplaene\/kerncurricula\/sekundarstufe-i-kerncurricula","quote":"Die Lernenden erklären Entstehung und Verlauf von Hochwasser als naturräumlichen Prozess und bewerten technische wie naturnahe Schutzmaßnahmen.","kompetenz_id":2}
{"id":1126,"country":"DE","subject":"Erdkunde","school_type":"Gymnasium (G9)","grade":"Jg. 57","title":"Orientierung auf der Erde — Gradnetz und topografische Karten","reference":"Kernlehrplan Erdkunde Sek I Gymnasium NRW (ab 2019\/20)","reference_url":"https:\/\/lehrplannavigator.nrw.de\/sekundarstufe-i\/kernlehrplaene-fuer-das-gymnasium-aufsteigend-ab-20192020","quote":"Die Schülerinnen und Schüler lesen und interpretieren thematische Karten, nutzen das Gradnetz zur Lagebestimmung und beschreiben physische Strukturen Mitteleuropas und der Alpen.","kompetenz_id":3}
{"id":1129,"country":"DE","subject":"Erdkunde","school_type":"Gymnasium (Sek I)","grade":"Jg. 57","title":"Orientierung auf der Erde — Gradnetz und thematische Karten","reference":"Niedersächsisches Kerncurriculum Gymnasium Sek I — Erdkunde","reference_url":"https:\/\/cuvo.nibis.de\/cuvo.php?p=download&upload=61","quote":"Die Schülerinnen und Schüler orientieren sich mithilfe des Gradnetzes, werten thematische Karten aus und beschreiben physiogeografische Grundstrukturen Europas.","kompetenz_id":3}
{"id":1147,"country":"DE","subject":"Erdkunde","school_type":"Gymnasium \/ Realschule","grade":"Jg. 79","title":"Stadt- und Siedlungsstrukturen — Wandel und Planung","reference":"Hessisches Kerncurriculum Sekundarstufe I — Erdkunde","reference_url":"https:\/\/kultus.hessen.de\/unterricht\/kerncurricula-und-lehrplaene\/kerncurricula\/sekundarstufe-i-kerncurricula","quote":"Die Lernenden beschreiben Prozesse der Stadtentwicklung in Deutschland und Europa und bewerten Konzepte nachhaltiger Raumordnung.","kompetenz_id":4}
{"id":1085,"country":"DE","subject":"Geographie","school_type":"Sek I","grade":"Jg. 910","title":"Klimawandel als globale Herausforderung","reference":"Rahmenlehrplan Teil C Geografie (Berlin\/Brandenburg)","reference_url":"https:\/\/bildungsserver.berlin-brandenburg.de\/unterricht\/rahmenlehrplaene","quote":"Die Schülerinnen und Schüler erklären Ursachen und Folgen des globalen Klimawandels und bewerten Maßnahmen der Klimaanpassung und des Klimaschutzes.","kompetenz_id":1}
{"id":1086,"country":"DE","subject":"Geographie","school_type":"Gymnasium","grade":"Jg. 9","title":"Der Mensch im Ökosystem Erde — anthropogener Klimawandel","reference":"LehrplanPLUS Bayern, Gymnasium Geographie 9","reference_url":"https:\/\/www.lehrplanplus.bayern.de\/fachlehrplan\/gymnasium\/9\/geographie","quote":"Die Schülerinnen und Schüler beurteilen Ursachen und Folgen des anthropogen verstärkten Treibhauseffekts und erläutern internationale Klimaschutzabkommen.","kompetenz_id":1}
{"id":1106,"country":"DE","subject":"Geographie","school_type":"Sek I","grade":"Jg. 56","title":"Hochwasser als naturräumlicher Prozess — Gestaltung der Erdoberfläche","reference":"Bildungsplan BW 2016, Geographie Sek I, IK 5\/6, Kap. 3.1.1.2","reference_url":"https:\/\/www.bildungsplaene-bw.de\/,Lde\/Startseite\/BP2016BW_ALLG\/BP2016BW_ALLG_SEK1_GEO_IK_5-6_01_02","quote":"Die Schülerinnen und Schüler analysieren Entstehung und Verlauf von Hochwasserereignissen und bewerten technische sowie naturnahe Schutzkonzepte.","kompetenz_id":2}
{"id":1110,"country":"DE","subject":"Geographie","school_type":"Gymnasium","grade":"Jg. 89","title":"Naturrisiken in Deutschland — Hochwasser und Muren","reference":"Lehrplan Gymnasium Geographie 2004\/2019 (Sachsen)","reference_url":"https:\/\/www.schulportal.sachsen.de\/lplandb\/lehrplan\/74","quote":"Die Schülerinnen und Schüler analysieren regionale Naturrisiken in Sachsen und Mitteleuropa und diskutieren technische und natürliche Schutzkonzepte.","kompetenz_id":2}
{"id":1130,"country":"DE","subject":"Geographie","school_type":"Gymnasium (Sek I)","grade":"Jg. 510","title":"Kartenarbeit und topografische Grundkenntnisse","reference":"Bildungsplan Gymnasium Sek I — Geographie (Hamburg)","reference_url":"https:\/\/www.hamburg.de\/resource\/blob\/123438\/90e4cf7b25114e17d1ac1f5c19c7b4f2\/geographie-gym-seki-data.pdf","quote":"Die Lernenden nutzen Karten, Gradnetz und digitale Geomedien, um sich räumlich zu orientieren und Lagebeziehungen zu beschreiben.","kompetenz_id":3}
{"id":1144,"country":"DE","subject":"Geographie","school_type":"Gymnasium","grade":"Jg. 7","title":"Stadt- und Raumstrukturen in Europa","reference":"LehrplanPLUS Bayern, Gymnasium Geographie 7","reference_url":"https:\/\/www.lehrplanplus.bayern.de\/fachlehrplan\/gymnasium\/7\/geographie","quote":"Die Schülerinnen und Schüler beschreiben Prozesse der Stadtentwicklung, erklären Zersiedelung und Verdichtung und bewerten nachhaltige Stadtkonzepte.","kompetenz_id":4}
{"id":1148,"country":"DE","subject":"Geographie","school_type":"Gymnasium (Sek I)","grade":"Jg. 710","title":"Hamburg als städtischer Raum — Stadtentwicklung und Nachhaltigkeit","reference":"Bildungsplan Gymnasium Sek I — Geographie (Hamburg)","reference_url":"https:\/\/www.hamburg.de\/resource\/blob\/123438\/90e4cf7b25114e17d1ac1f5c19c7b4f2\/geographie-gym-seki-data.pdf","quote":"Hamburg als verpflichtender Raumbezug: Schülerinnen und Schüler analysieren urbane Strukturen, treffen nachhaltige Gestaltungsentscheidungen und diskutieren Flächennutzungskonflikte.","kompetenz_id":4}
{"id":1091,"country":"DE","subject":"Geographie (national)","school_type":"Mittlerer Schulabschluss","grade":"Jg. 10","title":"Bildungsstandards Geographie — Anthropogener Klimawandel","reference":"DGfG — Bildungsstandards im Fach Geographie für den Mittleren Schulabschluss (10. Aufl. 2020)","reference_url":"https:\/\/geographie.de\/publikationen\/","quote":"Die Bildungsstandards fordern die Analyse des Mensch-Umwelt-Systems und der anthropogenen Einflüsse auf das Klima als Querschnittskompetenz.","kompetenz_id":1}
{"id":1123,"country":"DE","subject":"Geographie (national)","school_type":"Mittlerer Schulabschluss","grade":"Jg. 10","title":"Bildungsstandards Geographie — Naturgefahren und Risikoräume","reference":"DGfG — Bildungsstandards im Fach Geographie (10. Aufl. 2020)","reference_url":"https:\/\/geographie.de\/publikationen\/","quote":"Die DGfG-Standards fordern das Erkennen, Analysieren und Bewerten von Risikoräumen (Hochwasser, Hang­rutschung, Dürre) als Querschnitts­kompetenz der geographischen Bildung.","kompetenz_id":2}
{"id":1141,"country":"DE","subject":"Geographie (national)","school_type":"Mittlerer Schulabschluss","grade":"Jg. 10","title":"Bildungsstandards Geographie — Räumliche Orientierung","reference":"DGfG — Bildungsstandards im Fach Geographie (10. Aufl. 2020)","reference_url":"https:\/\/geographie.de\/publikationen\/","quote":"Räumliche Orientierung (Gradnetz, Karten, Atlanten, GIS) ist eine der sechs Kompetenzbereiche der Bildungsstandards Geographie und damit verbindliche Querschnittsvorgabe.","kompetenz_id":3}
{"id":1159,"country":"DE","subject":"Geographie (national)","school_type":"Mittlerer Schulabschluss","grade":"Jg. 10","title":"Bildungsstandards Geographie — Urbanisierung und Stadtstrukturen","reference":"DGfG — Bildungsstandards im Fach Geographie (10. Aufl. 2020)","reference_url":"https:\/\/geographie.de\/publikationen\/","quote":"Die DGfG-Standards fordern das Analysieren und Bewerten von Urbanisierungsprozessen und Stadt­strukturen im globalen Vergleich als Querschnittskompetenz.","kompetenz_id":4}
{"id":1103,"country":"LI","subject":"BNE — Klimakompetenz","school_type":"Sek I","grade":"7.9. Schulstufe","title":"LiLe — BNE-Rahmen","reference":"Liechtensteiner Lehrplan (LiLe), BNE-Perspektive Klima","reference_url":"https:\/\/fl.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Der LiLe orientiert sich am Lehrplan 21 und bindet Klimawandel an die BNE-Perspektive — fächerübergreifend angelegt in RZG, NT, WAH und ERG.","kompetenz_id":1}
{"id":1158,"country":"LI","subject":"BNE — Raumentwicklung Rheintal","school_type":"Sek I","grade":"7.9. Schulstufe","title":"LiLe — BNE-Perspektive Raumentwicklung","reference":"Liechtensteiner Lehrplan (LiLe), BNE-Rahmen","reference_url":"https:\/\/fl.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Die Zersiedelung im Rheintal ist ein prägendes Thema für Liechtenstein — der LiLe bindet es als BNE-Querschnitt an Mobilität, Ressourcenverbrauch und politische Gestaltung.","kompetenz_id":4}
{"id":1122,"country":"LI","subject":"BNE — Rheintal und Schutzbauten","school_type":"Sek I","grade":"7.9. Schulstufe","title":"LiLe — BNE-Perspektive Rheintal","reference":"Liechtensteiner Lehrplan (LiLe), BNE-Rahmen","reference_url":"https:\/\/fl.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Der LiLe bindet das Thema Hochwasser am Alpenrhein fächerübergreifend an BNE — inkl. Schutzdämmen, Retentionsflächen und der internationalen Zusammenarbeit SchweizLiechtenstein–Österreich.","kompetenz_id":2}
{"id":1088,"country":"LI","subject":"RZG","school_type":"Sek I","grade":"7.9. Schulstufe","title":"Klimawandel — globale und lokale Perspektive","reference":"Liechtensteiner Lehrplan (LiLe) — RZG","reference_url":"https:\/\/fl.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Die Lernenden verstehen den anthropogenen Klimawandel und reflektieren Handlungsoptionen auf persönlicher, nationaler und globaler Ebene.","kompetenz_id":1}
{"id":1108,"country":"LI","subject":"RZG","school_type":"Sek I","grade":"7.9. Schulstufe","title":"Hochwasser am Alpenrhein","reference":"Liechtensteiner Lehrplan (LiLe) — Lebensraum Rhein","reference_url":"https:\/\/fl.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Die Lernenden erfassen Hochwasser als Naturgefahr im Rheintal und reflektieren die Bedeutung von Schutzdämmen und Retentionsräumen.","kompetenz_id":2}
{"id":1128,"country":"LI","subject":"RZG","school_type":"Sek I","grade":"7.9. Schulstufe","title":"Alpen und Alpenvorland — räumliche Gliederung","reference":"Liechtensteiner Lehrplan (LiLe)","reference_url":"https:\/\/www.lile.li\/","quote":"Die Lernenden beschreiben die Höhenstufen und topografischen Besonderheiten der Alpen und orientieren sich mit Karten und Koordinaten im Alpenraum.","kompetenz_id":3}
{"id":1146,"country":"LI","subject":"RZG","school_type":"Sek I","grade":"7.9. Schulstufe","title":"Siedlungsentwicklung in Liechtenstein","reference":"Liechtensteiner Lehrplan (LiLe) — RZG","reference_url":"https:\/\/fl.lehrplan.ch\/index.php?code=b%7C6%7C4","quote":"Die Lernenden setzen sich mit Zersiedelung und Verdichtung im Rheintal auseinander und diskutieren Konsequenzen für Verkehr, Versorgung und Landschaft.","kompetenz_id":4}
@@ -1,242 +0,0 @@
<?php
// Phase-1-Validierung der lehrplan_anchors gegen Live-URLs und Verordnungstexte
// Erzeugt: lehrplan-validierung-phase1.json
declare(strict_types=1);
$lines = file(__DIR__ . '/anchors-dump.jsonl', FILE_IGNORE_NEW_LINES);
$results = [];
// ---- Verifizierte Fakten aus dieser Validierungssitzung ----
// 1. https://www.ris.bka.gv.at/.../Gesetzesnummer=20007850 -> 200 OK, GeltendeFassung, "Verordnung der Bundesministerin
// fuer Unterricht, Kunst und Kultur ueber die Lehrplaene der Mittelschulen" (BGBl. II 185/2012 in der Fassung BGBl. II 1/2023).
// Offizielle Fachnamen 2023:
// - "Geografie und wirtschaftliche Bildung" (nicht "Geographie und Wirtschaftskunde", nicht "GW")
// - "Geschichte und Politische Bildung" (als EIN Fach)
// - "Digitale Grundbildung" (nicht "Informatische Bildung")
// - "Biologie und Umweltbildung"
// - "Chemie", "Physik", "Mathematik", "Deutsch", "Bewegung und Sport", "Ernaehrung und Haushalt"
// Uebergreifende Themen (NICHT eigenstaendige Faecher, sondern Querschnitt):
// - Informatische Bildung, Medienbildung, Gesundheitsfoerderung, Interkulturelle Bildung,
// Umweltbildung fuer nachhaltige Entwicklung, Verkehrs- und Mobilitaetsbildung,
// Wirtschafts-, Finanz- und Verbraucher/innenbildung, Politische Bildung (als reiner Querschnitt)
// 2. https://geographie.de/publikationen/ -> 404 Not Found (bestaetigt 2026-06-08).
// Alternativ-URL: https://vgdh.de/wp-content/uploads/2023/08/Bildungsstandards_Geographie_2020_Web.pdf (DGfG 2020, 10. Auflage)
// 3. https://kultus.hessen.de/.../sekundarstufe-i-kerncurricula -> 200 OK, listet Erdkunde Sek I PDFs (HS/RS/Gym).
// 4. https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/{7,9}/geographie -> 200 OK, "LehrplanPLUS" Bayern, aktuell (Schuljahr 2024/25 Flexibilisierung).
// 5. https://www.bildungsplaene-bw.de/.../BP2016BW_ALLG_SEK1_GEO_IK_5-6_01_02 -> 200 OK, BP 2016 BW.
// 6. https://lehrplannavigator.nrw.de/sekundarstufe-i/kernlehrplaene-fuer-das-gymnasium-aufsteigend-ab-20192020 -> 200 OK,
// Kernlehrplan Erdkunde Gymnasium SI (2019) verlinkt.
// 7. https://static.bildung-rp.de/.../Ek_G_Sk_Sek_I__LP_2021_.pdf -> 200 OK (PDF Binary), Dateiname suggeriert RP 2021,
// Inhalt nicht extrahierbar via WebFetch -> needs_human_review fuer Quote-Verifikation.
// 8. https://bildungsserver.berlin-brandenburg.de/unterricht/rahmenlehrplaene -> 200 OK,
// Berlin/Brandenburg Portalseite, verlinkt zu Rahmenlehrplaenen (kein Direkt-PDF zu Geografie Teil C).
// 9. https://www.hamburg.de/.../geographie-gym-seki-data.pdf -> 200 OK (PDF Binary), HH Geographie Gym Sek I,
// Volltext nicht extrahierbar -> needs_human_review fuer Quote-Verifikation.
// 10. https://www.schulportal.sachsen.de/lplandb/lehrplan/74 -> 200 OK, "Lehrplan Gymnasium Geographie",
// gueltig 2004/2009/2011/2019. Aelter als BW/Bayern/HE, aber LAUT QUELLE NOCH GUELTIG.
// -> Markierung "version_outdated" NICHT angebracht (er gilt offiziell). Hinweis in details.
// 11. https://cuvo.nibis.de/cuvo.php?p=download&upload=61 -> HTTP 403 fuer WebFetch (Bot-Block).
// URL-Pfad ueber sicheres Portal (cuvo.nibis.de = Niedersaechsisches Kerncurriculum-Portal).
// -> needs_human_review fuer URL-Liveness (nicht definitiv tot, nur fuer Bots blockiert).
// 12. https://v-fe.lehrplan.ch/index.php?code=... und https://fl.lehrplan.ch/index.php?code=... -> HTTP 403 fuer WebFetch.
// v-fe.lehrplan.ch = "Vorlage Lehrplan 21" (Generische Vorlage, Kantone forken davon).
// fl.lehrplan.ch = LiLe (Liechtensteiner Lehrplan, basiert auf Lehrplan 21, seit 2019 in Kraft).
// Beide Domains sind gemaess Web-Recherche aktiv -> needs_human_review fuer URL-Liveness.
// 13. https://www.lile.li/ -> 200 OK, Schulamt Liechtenstein, Portal-Seite (kein Direkt-Lehrplan-Pfad).
// 14. AT-Quotes sind in der Datenbank ueberwiegend als REDAKTIONELLE PARAPHRASEN formuliert
// ("Klimawandel wird im Fach Biologie und Umweltbildung ueber Oekosysteme ... behandelt"),
// nicht als woertliche Zitate aus dem Verordnungstext. Ohne Volltext-Diff
// kann ich Quote-Treue nicht abschliessend pruefen -> "needs_human_review" mit Hinweis,
// ausser bei direkt erkennbar woertlichen Passagen aus RIS-Verordnung.
// Direkte Zitate (erkennbar an Lehrplan-Formulierung): IDs 1082, 1083, 1084, 1104, 1105,
// 1124, 1125, 1142, 1143, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170,
// 1171, 1172, 1182, 1183, 1184, 1190, 1191, 1198, 1199, 1200, 1206, 1209, 1210, 1213, 1214,
// 1215, 1221.
// Subject-Whitelisten pro Land
$at_subjects_official_facher = [
'Geografie und wirtschaftliche Bildung','Geschichte und Politische Bildung','Geschichte und politische Bildung',
'Digitale Grundbildung','Biologie und Umweltbildung','Chemie','Physik','Mathematik','Deutsch',
'Bewegung und Sport','Ernaehrung und Haushalt','Ernährung und Haushalt','Kunst und Gestaltung','Musik','Technik und Design',
];
$at_subjects_querschnitt = [
'Umweltbildung für nachhaltige Entwicklung','Verkehrs- und Mobilitätsbildung',
'Wirtschafts-, Finanz- und Verbraucher:innenbildung','Gesundheitsförderung','Medienbildung',
'Interkulturelle Bildung','Informatische Bildung','Politische Bildung',
];
$ch_subjects_lehrplan21 = [
'RZG','RZG (Räume, Zeiten, Gesellschaften)','Natur und Technik (NT)','Wirtschaft, Arbeit, Haushalt (WAH)',
'Mathematik','Medien und Informatik (MI)','Ethik, Religionen, Gemeinschaft (ERG)',
'BNE — Natürliche Umwelt und Ressourcen','BNE — Wirtschaft und Konsum',
'Überfachliche Kompetenzen — Methodische',
];
$li_subjects = ['RZG','BNE — Klimakompetenz','BNE — Raumentwicklung Rheintal','BNE — Rheintal und Schutzbauten'];
// URL-Status-Map (verifiziert in dieser Session)
$url_status = [
'https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850' => 'live',
'https://geographie.de/publikationen/' => 'dead404',
'https://kultus.hessen.de/unterricht/kerncurricula-und-lehrplaene/kerncurricula/sekundarstufe-i-kerncurricula' => 'live',
'https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/9/geographie' => 'live',
'https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/7/geographie' => 'live',
'https://www.bildungsplaene-bw.de/,Lde/Startseite/BP2016BW_ALLG/BP2016BW_ALLG_SEK1_GEO_IK_5-6_01_02' => 'live',
'https://lehrplannavigator.nrw.de/sekundarstufe-i/kernlehrplaene-fuer-das-gymnasium-aufsteigend-ab-20192020' => 'live',
'https://static.bildung-rp.de/lehrplaene/gesellschaftswissenschaften/Ek_G_Sk_Sek_I__LP_2021_.pdf' => 'live_pdf_unread',
'https://bildungsserver.berlin-brandenburg.de/unterricht/rahmenlehrplaene' => 'live_portal',
'https://www.hamburg.de/resource/blob/123438/90e4cf7b25114e17d1ac1f5c19c7b4f2/geographie-gym-seki-data.pdf' => 'live_pdf_unread',
'https://www.schulportal.sachsen.de/lplandb/lehrplan/74' => 'live',
'https://cuvo.nibis.de/cuvo.php?p=download&upload=61' => 'botblock_403',
'https://www.lile.li/' => 'live_portal',
];
// Direkt-Zitate aus AT-RIS (erkennbar woertliche Lehrplan-Formulierungen)
$at_direct_quotes = [1082,1083,1084,1104,1105,1124,1125,1142,1143,1160,1161,1162,1163,1164,1165,1166,1167,1168,1169,1170,1171,1172,1182,1183,1184,1190,1191,1198,1199,1200,1206,1209,1210,1213,1214,1215,1221];
foreach ($lines as $l) {
$r = json_decode($l, true);
$id = (int)$r['id'];
$country = $r['country'];
$subject = $r['subject'];
$url = $r['reference_url'];
$status = null;
$details = [];
$fix = null;
// Parse host for lehrplan.ch family
$host = parse_url($url, PHP_URL_HOST);
$is_lehrplan_ch = ($host === 'v-fe.lehrplan.ch' || $host === 'fl.lehrplan.ch');
// -- 1. URL-Status pruefen
$url_state = $url_status[$url] ?? ($is_lehrplan_ch ? 'botblock_403' : 'unknown');
if ($url_state === 'dead404') {
$status = 'url_dead';
$details[] = 'reference_url liefert HTTP 404 (verifiziert 2026-06-08 via WebFetch).';
if (str_contains($url, 'geographie.de/publikationen/')) {
$fix = 'reference_url ersetzen durch https://vgdh.de/wp-content/uploads/2023/08/Bildungsstandards_Geographie_2020_Web.pdf (DGfG 2020, 10. Auflage, durch WebSearch bestaetigt)';
}
}
// -- 2. AT-Subject pruefen
if ($status === null && $country === 'AT') {
if ($subject === 'GW') {
// Bekannter Lehrer-Code, ABER seit Lehrplan 2023 heisst das Fach offiziell "Geografie und wirtschaftliche Bildung".
$status = 'needs_human_review';
$details[] = 'Subject "GW" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1/2023 lautet "Geografie und wirtschaftliche Bildung". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).';
$fix = 'Optional: Subject auf "Geografie und wirtschaftliche Bildung" angleichen (offizielle Bezeichnung 2023).';
} elseif ($subject === 'Politische Bildung') {
// Politische Bildung ist KEIN eigenstaendiges Fach mehr, sondern Teil von "Geschichte und Politische Bildung" und Querschnittsthema.
$status = 'subject_wrong';
$details[] = 'Im AT-Lehrplan 2023 (BGBl. II 1/2023) gibt es kein eigenstaendiges Pflichtfach "Politische Bildung". Politische Bildung ist (a) Teil des Fachs "Geschichte und Politische Bildung" und (b) Querschnittsthema. Reference-URL ist korrekt (RIS), aber Subject suggeriert ein nicht existierendes Fach.';
$fix = 'Subject auf "Geschichte und Politische Bildung" aendern ODER Quelle als Querschnittsthema kennzeichnen (z. B. "Querschnitt: Politische Bildung").';
} elseif ($subject === 'Informatische Bildung') {
// Im 2023er Lehrplan: Querschnittsthema; das eigenstaendige Pflichtfach heisst "Digitale Grundbildung".
$status = 'subject_wrong';
$details[] = 'Im AT-Lehrplan 2023 ist "Informatische Bildung" Querschnittsthema; das eigenstaendige Pflichtfach heisst "Digitale Grundbildung". Wenn der Anker ein Fach meinen soll, ist die Bezeichnung falsch.';
$fix = 'Subject auf "Digitale Grundbildung" aendern (wenn Fach gemeint) ODER explizit als "Querschnitt: Informatische Bildung" auszeichnen.';
} elseif (in_array($subject, $at_subjects_official_facher, true) || in_array($subject, $at_subjects_querschnitt, true)) {
// Subject ist entweder offizielles Fach oder dokumentiertes Querschnittsthema in der Verordnung.
if (in_array($id, $at_direct_quotes, true)) {
$status = 'ok';
$details[] = 'Subject in BGBl. II 1/2023 dokumentiert (Fach oder Querschnittsthema). Quote folgt Lehrplan-Formulierung (Direkt-/Naheparaphrase). reference_url live.';
} else {
$status = 'needs_human_review';
$details[] = 'Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden.';
}
} else {
$status = 'needs_human_review';
$details[] = 'Subject "' . $subject . '" nicht in der bestaetigten AT-Fach-/Querschnitts-Liste. Manuell pruefen.';
}
}
// -- 3. CH-Subject + URL
if ($status === null && $country === 'CH') {
if (!in_array($subject, $ch_subjects_lehrplan21, true)) {
$status = 'needs_human_review';
$details[] = 'Subject "' . $subject . '" nicht in der Standard-Lehrplan-21-Fachbereichsliste. Manuell pruefen.';
} elseif (str_contains($subject, 'BNE')) {
// BNE ist im Lehrplan 21 Leitidee, nicht eigenstaendiger Code e|200|1. URL-Code ggf. nicht passend.
$status = 'needs_human_review';
$details[] = 'BNE ist im Lehrplan 21 als Leitidee/Querschnitt verankert, nicht als eigenstaendiger Fachbereich. Der URL-Code "e|200|1" verweist auf eine Lehrplan-Vorlagen-Sicht (v-fe = Vorlage Fremdevaluation/Entwurf). Aktuellster Ankerpunkt zu BNE ware lehrplan.ch/index.php?nav=overview oder kantonale Spezifizierungen. URL-Liveness wegen Bot-Block 403 nicht automatisch verifizierbar.';
$fix = 'Pruefen, ob ein expliziter LP21-BNE-Querverweis (z. B. https://www.lehrplan21.ch/grundlagen-bne) sinnvoller ist als der v-fe-Code.';
} else {
$status = 'needs_human_review';
$details[] = 'Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden.';
}
}
// -- 4. LI-Subject + URL
if ($status === null && $country === 'LI') {
if (!in_array($subject, $li_subjects, true)) {
$status = 'needs_human_review';
$details[] = 'Subject "' . $subject . '" liechtensteinspezifisch, nicht automatisch bewertbar.';
} elseif (str_contains($subject, 'BNE')) {
$status = 'needs_human_review';
$details[] = 'BNE im LiLe als Querschnittsperspektive vorhanden, aber URL-Code b|6|4 zeigt RZG (Fachbereich), nicht den BNE-Querverweis. Inhaltliche Bindung Geografie<->BNE ist plausibel, aber Quote/URL koppeln BNE-Marker an RZG-Seite. Manuell pruefen. URL-Liveness wegen Bot-Block nicht automatisch verifizierbar (fl.lehrplan.ch laut Web-Recherche aktiv).';
} else {
// LI:RZG
$status = 'needs_human_review';
$details[] = 'LiLe basiert auf Lehrplan 21 und ist seit 2019 gueltig. Subject RZG passt. URL-Liveness wegen Bot-Block (403) nicht automatisch verifiziert; Domain laut Web-Recherche aktiv. Quote ist redaktionelle Bruecke, nicht woertlich aus LiLe.';
}
}
// -- 5. DE-Subject + URL
if ($status === null && $country === 'DE') {
if ($subject === 'Erdkunde' || $subject === 'Geographie') {
// Beide Bezeichnungen je Bundesland korrekt.
if ($url_state === 'live') {
$status = 'ok';
$details[] = 'reference_url ist live (Portal-/Plan-Seite). Subject "' . $subject . '" entspricht offizieller Bezeichnung des verlinkten Bundesland-Lehrplans (HE/NRW: Erdkunde; BW/BY/HH/SN: Geographie; RP: Erdkunde im Verbund Gesellschaftswissenschaften).';
if (str_contains($url, 'schulportal.sachsen.de')) {
$details[] = 'Hinweis: SN-Lehrplan ist 2004 erstmals erlassen, mit Ueberarbeitungen 2009/2011/2019. Offiziell weiter gueltig laut Schulportal Sachsen - kein "version_outdated", aber inhaltlich der aelteste aktive Plan im Set.';
}
if ($url === 'https://kultus.hessen.de/unterricht/kerncurricula-und-lehrplaene/kerncurricula/sekundarstufe-i-kerncurricula') {
$details[] = 'Hinweis: Reference-URL ist Uebersichtsseite; das eigentliche KC-PDF (HS/RS/Gym) wird von dort verlinkt, aber nicht direkt angesteuert. Praeziserer Direkt-Link zu HE-Erdkunde-KC waere besser.';
}
} elseif ($url_state === 'live_portal') {
$status = 'needs_human_review';
$details[] = 'reference_url ist Portal-/Uebersichtsseite (bildungsserver.berlin-brandenburg.de/unterricht/rahmenlehrplaene), nicht der RLP-Teil C Geografie direkt. Der RLP 1-10 Berlin/Brandenburg ist gueltig (2017+), aber URL ist zu unspezifisch.';
$fix = 'Auf Direkt-PDF zu "Teil C Geografie" des Rahmenlehrplans 1-10 Berlin-Brandenburg verlinken (z. B. bildungsserver.berlin-brandenburg.de/.../rlp-1-10-online).';
} elseif ($url_state === 'live_pdf_unread') {
$status = 'needs_human_review';
$details[] = 'reference_url liefert PDF (200 OK), Volltext aus Bot-Sicht nicht extrahierbar. Dateiname und Titel suggerieren passendes Bundesland-/Fach-Dokument, aber Quote muss manuell gegen den PDF-Inhalt verglichen werden.';
} elseif ($url_state === 'botblock_403') {
$status = 'needs_human_review';
$details[] = 'reference_url WebFetch HTTP 403 (Bot-Block). Portal cuvo.nibis.de ist Niedersaechsisches Curriculum-Portal, gemaess Web-Recherche aktiv. URL-Liveness manuell verifizieren; Quote manuell pruefen.';
} else {
$status = 'needs_human_review';
$details[] = 'URL-Status unklar, manuell pruefen.';
}
} elseif ($subject === 'Geographie (national)') {
// bereits oben als url_dead behandelt
$status = $status ?? 'needs_human_review';
$details[] = 'DGfG-Bildungsstandards sind nationaler KMK-naher Bezugsrahmen, aber kein verbindlicher Lehrplan. Subject-Markierung "Geographie (national)" ist konzeptionell ok, sofern erkennbar.';
}
}
if ($status === null) {
$status = 'needs_human_review';
$details[] = 'Klassifikator hat keinen Treffer.';
}
$entry = [
'id' => $id,
'status' => $status,
'details' => implode(' ', $details),
];
if ($fix !== null) $entry['fix_suggestion'] = $fix;
$results[] = $entry;
}
// Sortiere nach id
usort($results, fn($a,$b)=>$a['id']<=>$b['id']);
file_put_contents(__DIR__ . '/lehrplan-validierung-phase1.json', json_encode($results, JSON_UNESCAPED_UNICODE|JSON_PRETTY_PRINT));
// Summary
$by_status = [];
foreach ($results as $r) $by_status[$r['status']] = ($by_status[$r['status']]??0)+1;
echo "TOTAL: ".count($results)."\n";
foreach ($by_status as $s=>$c) echo " $s: $c\n";
-139
View File
@@ -1,139 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Entwurfswerkzeug · GeoGraSim</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',system-ui,sans-serif;background:#f5f2eb;color:#2a2a2a;line-height:1.5;padding:24px;max-width:1100px;margin:0 auto}
h1{color:#1f4e5a;font-size:1.8rem;margin-bottom:4px}
.sub{font-size:0.85rem;color:#8a8a8a;margin-bottom:18px}
h2{color:#1f4e5a;font-size:1.15rem;margin:24px 0 8px;padding-bottom:4px;border-bottom:2px solid #4a7c8a}
h3{color:#4a7c8a;font-size:0.98rem;margin:18px 0 8px}
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:12px;margin:10px 0}
.card{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:14px 16px;text-decoration:none;color:inherit;display:block;transition:transform .12s,border-color .12s}
.card:hover{transform:translateY(-2px);border-color:#4a7c8a}
.card h4{color:#1f4e5a;font-size:.98rem;margin-bottom:4px}
.card p{font-size:.82rem;color:#666;line-height:1.4}
.card .meta{font-size:.7rem;color:#8a8a8a;margin-top:6px;font-family:'JetBrains Mono',Consolas,monospace}
table{width:100%;border-collapse:collapse;font-size:.86rem;margin:6px 0;background:#fff;border-radius:8px;overflow:hidden}
th,td{text-align:left;padding:8px 12px;border-bottom:1px solid #e0ddd4;vertical-align:top}
th{background:#1f4e5a;color:#fff;font-weight:600;font-size:.78rem;text-transform:uppercase}
tr:last-child td{border-bottom:none}
code{background:#f5f2eb;padding:2px 6px;border-radius:3px;font-family:'JetBrains Mono',Consolas,monospace;font-size:.85em}
a{color:#1f4e5a}
.badge{display:inline-block;font-size:.7rem;font-weight:700;padding:2px 7px;border-radius:9999px;margin-right:4px}
.b-delete{background:#fde0db;color:#9c4d2e}
.b-legacy{background:#e7e3d6;color:#6b6448}
.b-archive{background:#e3e9d6;color:#4a6b3f}
.b-tool{background:#d6e3e9;color:#1f4e5a}
.b-info{background:#e8c547;color:#5a4416}
.note-box{background:#fff7e0;border-left:4px solid #d2a24c;padding:12px 16px;margin:14px 0;border-radius:0 8px 8px 0;font-size:.92rem}
.top-nav{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:10px 14px;margin-bottom:18px;font-size:.88rem;display:flex;flex-wrap:wrap;gap:14px;align-items:center}
.top-nav a{text-decoration:none;padding:6px 12px;border-radius:6px}
.top-nav a:hover{background:#f5f2eb}
.top-nav a.active{background:#1f4e5a;color:#fff}
.meta-line{font-size:.78rem;color:#8a8a8a;margin-top:2px}
</style>
</head>
<body>
<nav class="top-nav">
<strong>🛠 Entwurfswerkzeug</strong>
<a href="index.html" class="active">Übersicht</a>
<a href="../entwurf.html">Entwurf</a>
<a href="../review.html">Review</a>
<a href="accounts.html">🔑 Accounts</a>
<a href="standards.html">📐 Standards</a>
<a href="legacy/" style="color:#6b6448">📂 legacy/</a>
<a href="toDelete/" style="color:#9c4d2e">📂 toDelete/</a>
<a href="../../App/admin-sitemap.html" target="_blank">📊 Sitemap</a>
</nav>
<h1>🛠 Entwurfswerkzeug</h1>
<p class="sub">Lokaler Arbeitsbereich für Entwicklungs-Doku, Legacy-Sichtung und Lösch-Kandidaten. Liegt unter <code>.dontDeploy/entwurfswerkzeug/</code> — wird nie deployed.</p>
<div class="note-box">
<b>Prinzip:</b> Nichts wird gelöscht. Alles, was aus dem Prod-Verzeichnis rausfällt, landet hier — zur späteren Entscheidung.
Wenn du ein File brauchst: einfach zurückverschieben mit <code>git mv .dontDeploy/entwurfswerkzeug/toDelete/X.html App/X.html</code>.
</div>
<h2>📁 Hauptbereiche</h2>
<div class="grid">
<a class="card" href="legacy/">
<h4><span class="badge b-legacy">legacy</span> Sichtungs-Halde</h4>
<p>Test-Tools, Demo-Mockups, alte Versionen — zum Ansehen noch da, aber aus der Prod entfernt.</p>
<div class="meta">.dontDeploy/entwurfswerkzeug/legacy/</div>
</a>
<a class="card" href="toDelete/">
<h4><span class="badge b-delete">toDelete</span> Lösch-Kandidaten</h4>
<p>Stand: Subagent-Sweep 2026-06-08. 11 Standalone-HTMLs vom Wrapper-System abgelöst. Warten auf Lösch-Freigabe.</p>
<div class="meta">.dontDeploy/entwurfswerkzeug/toDelete/</div>
</a>
<a class="card" href="legacy/sims-archive/">
<h4><span class="badge b-archive">sims-archive</span> Alte Sim-Entwürfe</h4>
<p>Vorgänger-Stände einzelner Sims (z.B. Klima-Plane-Test). Pro Sim ein Ordner.</p>
<div class="meta">legacy/sims-archive/</div>
</a>
<a class="card" href="../entwurf.html">
<h4><span class="badge b-tool">entwurf.html</span> Architektur-Doku</h4>
<p>Lebendes Doku-File. Codes A/B/C/D/K/L/N/Z, Konsistenz-Matrix, Sitemap, Change-Log.</p>
<div class="meta">.dontDeploy/entwurf.html</div>
</a>
<a class="card" href="../review.html">
<h4><span class="badge b-tool">review.html</span> Review-Notizen</h4>
<p>Iterations-Notizen + Stand der offenen Themen.</p>
<div class="meta">.dontDeploy/review.html</div>
</a>
<a class="card" href="../../App/admin-sitemap.html" target="_blank">
<h4><span class="badge b-info">admin-sitemap</span> Live-Sitemap</h4>
<p>Vollständige Übersicht aller 81 Prod-Seiten + Tote Links + Orphan-Liste. Wird im App-Admin-Bereich ausgeliefert.</p>
<div class="meta">App/admin-sitemap.html</div>
</a>
<a class="card" href="accounts.html">
<h4><span class="badge b-info">accounts</span> 🔑 Test-Accounts</h4>
<p>Schneller Login-Überblick: 7 Lehrer + 16 Schüler lokal, 17 Lehrer + ~70 Schüler auf Prod. Klassen-Codes, Passwörter, Display-Namen.</p>
<div class="meta">.dontDeploy/entwurfswerkzeug/accounts.html</div>
</a>
</div>
<h2>📋 toDelete/ — Aktuelle Lösch-Kandidaten</h2>
<table>
<thead><tr><th>Datei</th><th>Was es war</th><th>Status / Empfehlung</th></tr></thead>
<tbody>
<tr><td><code>dashboard.html</code></td><td>Demo-Mockup mit „alle Daten erfunden"-Banner</td><td>Ersetzt durch <code>teacher.html</code>. Endgültig löschbar.</td></tr>
<tr><td><code>game.html</code></td><td>Klima-2D Standalone (vor Wrapper-System)</td><td>Wrapper <code>pages/klima.php</code> ist Production. Endgültig löschbar.</td></tr>
<tr><td><code>game-3d.html</code></td><td>Klima-3D Standalone</td><td>Wrapper <code>pages/klima-3d.php</code> ist Production. Endgültig löschbar.</td></tr>
<tr><td><code>fluss.html</code></td><td>Flussmanagement Standalone</td><td>Wrapper <code>pages/fluss.php</code> ist Production. Endgültig löschbar.</td></tr>
<tr><td><code>heli.html</code></td><td>Heli-Navigation Standalone</td><td>Wrapper <code>pages/heli.php</code> ist Production. Endgültig löschbar.</td></tr>
<tr><td><code>stadt.html</code></td><td>Stadt-Simulation Standalone (nie fertig)</td><td>Stadt ist noch in Entwurf — beim Reaktivieren ggf. zurückholen.</td></tr>
<tr><td><code>erdbeben.html</code></td><td>Konzept-Stub Erdbeben-Sim</td><td>Konzept nie umgesetzt. Löschbar.</td></tr>
<tr><td><code>energiemix.html</code></td><td>Konzept-Stub Energiemix</td><td>Ersetzt durch <code>energiemanager</code>. Löschbar.</td></tr>
<tr><td><code>lieferketten.html</code></td><td>Konzept-Stub Lieferketten</td><td>Konzept nie umgesetzt. Löschbar.</td></tr>
<tr><td><code>regenwald.html</code></td><td>Konzept-Stub Regenwald</td><td>Konzept nie umgesetzt. Löschbar.</td></tr>
</tbody>
</table>
<h2>📋 legacy/ — Sichtungs-Material (nicht löschen)</h2>
<table>
<thead><tr><th>Datei</th><th>Zweck</th><th>Empfehlung</th></tr></thead>
<tbody>
<tr><td><code>tile-test.html</code></td><td>Test-Tool für Tile-Layouts</td><td>Behalten — gelegentlich nützlich beim Layout-Debugging.</td></tr>
<tr><td><code>sims-archive/klima-plane-test.html</code></td><td>Klima-3D Plane-Test (alter Stand)</td><td>Behalten als Referenz, falls 3D-Logik überarbeitet wird.</td></tr>
</tbody>
</table>
<h2>🔗 Quick-Links</h2>
<div class="grid">
<a class="card" href="http://localhost/geograsim/App/" target="_blank"><h4>🌐 Lokaler Sim-Server</h4><p>Lokale Prod-Sicht der App.</p></a>
<a class="card" href="https://geograsim.at/" target="_blank"><h4>🌐 Production</h4><p>geograsim.at — Test+Live.</p></a>
<a class="card" href="http://localhost/geograsim/App/admin-sitemap.html" target="_blank"><h4>📊 Sitemap</h4><p>Vollständige Page-Übersicht inkl. Tote-Links.</p></a>
<a class="card" href="http://localhost/geograsim/App/admin-styleguide.html" target="_blank"><h4>🎨 Styleguide</h4><p>Design-Tokens, Komponenten.</p></a>
</div>
<footer style="margin:32px 0 24px;text-align:center;font-size:.78rem;color:#8a8a8a">
Erstellt: 2026-06-08 · Stand-Sweep: 11 Pages in <code>toDelete/</code>, 2 in <code>legacy/</code>.
</footer>
</body>
</html>
@@ -1,75 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>legacy/ · Entwurfswerkzeug</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',system-ui,sans-serif;background:#f5f2eb;color:#2a2a2a;line-height:1.5;padding:24px;max-width:1100px;margin:0 auto}
h1{color:#1f4e5a;font-size:1.5rem;margin-bottom:4px}
.sub{font-size:.82rem;color:#8a8a8a;margin-bottom:14px}
h2{color:#1f4e5a;font-size:1.05rem;margin:20px 0 8px;padding-bottom:4px;border-bottom:2px solid #4a7c8a}
table{width:100%;border-collapse:collapse;font-size:.86rem;background:#fff;border-radius:6px;overflow:hidden}
th,td{text-align:left;padding:8px 12px;border-bottom:1px solid #e0ddd4;vertical-align:top}
th{background:#6b6448;color:#fff;font-weight:600;font-size:.74rem;text-transform:uppercase;letter-spacing:.04em}
tr:last-child td{border-bottom:none}
code{background:#f5f2eb;padding:2px 6px;border-radius:3px;font-family:'JetBrains Mono',Consolas,monospace;font-size:.85em}
a{color:#1f4e5a}
.note-box{background:#fff7e0;border-left:4px solid #d2a24c;padding:10px 14px;margin:12px 0;border-radius:0 6px 6px 0;font-size:.86rem}
/* einheitliches Entwurfswerkzeug-Menü */
.top-nav{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:10px 14px;margin-bottom:18px;font-size:.86rem;display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.top-nav strong{color:#1f4e5a}
.top-nav a{text-decoration:none;padding:5px 11px;border-radius:6px;color:#1f4e5a}
.top-nav a:hover{background:#f5f2eb}
.top-nav a.active{background:#1f4e5a;color:#fff}
</style>
</head>
<body>
<nav class="top-nav">
<strong>🛠 Entwurfswerkzeug</strong>
<a href="../index.html">Übersicht</a>
<a href="../../entwurf.html">Entwurf</a>
<a href="../../review.html">Review</a>
<a href="../accounts.html">🔑 Accounts</a>
<a href="index.html" class="active" style="background:#6b6448;color:#fff">📂 legacy/</a>
<a href="../toDelete/" style="color:#9c4d2e">📂 toDelete/</a>
<a href="../../../App/admin-sitemap.html" target="_blank">📊 Sitemap</a>
</nav>
<h1>📂 legacy/</h1>
<p class="sub">Sichtungs-Material — alte Test-Tools, Stände, gelegentlich nützlich. Wird <strong>behalten</strong>, nicht gelöscht.</p>
<div class="note-box">
Im Unterschied zu <code>toDelete/</code>: was hier liegt, hat noch eine zukünftige Funktion (Layout-Debugging, Referenz-Stand).
</div>
<h2>📄 Dateien</h2>
<table>
<thead><tr><th>Datei</th><th>Zweck</th><th>Stand</th></tr></thead>
<tbody>
<tr>
<td><a href="tile-test.html"><code>tile-test.html</code></a></td>
<td>Test-Tool für Tile-Layouts (Sim-Card-Grid auf der Startseite)</td>
<td>aus Prod entfernt 2026-06-08</td>
</tr>
</tbody>
</table>
<h2>📁 Unterordner</h2>
<table>
<thead><tr><th>Pfad</th><th>Inhalt</th></tr></thead>
<tbody>
<tr>
<td><a href="sims-archive/"><code>sims-archive/</code></a></td>
<td>Vorgänger-Stände einzelner Sims. Bisher: <code>klima-plane-test.html</code> (alter 3D-Plane-Test).</td>
</tr>
</tbody>
</table>
<footer style="margin:24px 0;text-align:center;font-size:.75rem;color:#8a8a8a">
Liegt unter <code>.dontDeploy/entwurfswerkzeug/legacy/</code> · wird nicht deployed.
</footer>
</body>
</html>
@@ -1,232 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Flugzeug-Orientierungs-Test</title>
<style>
body { margin: 0; font-family: sans-serif; background: #e4ecf0; }
#scene { width: 100vw; height: calc(100dvh - 200px); }
#controls {
position: fixed; bottom: 0; left: 0; right: 0; height: 200px;
background: #1a2a32; color: #fff; padding: 14px 22px;
display: grid; grid-template-columns: 1fr 1fr 1fr 1fr; gap: 10px 24px;
box-shadow: 0 -4px 12px rgba(0,0,0,0.3);
}
.slider-row { display: flex; flex-direction: column; gap: 2px; }
.slider-row label { font-size: 12px; font-weight: 700; color: #b8d0e0; }
.slider-row input[type=range] { width: 100%; }
.slider-row .val { font-family: monospace; font-size: 13px; color: #7cfae0; }
.note { grid-column: 1 / -1; font-size: 12px; color: #a0b8c8; line-height: 1.5; }
.big { grid-column: 1 / -1; text-align: center; font-size: 15px; font-weight: 700; }
button { padding: 6px 14px; background: #3a7a8a; color: #fff; border: none;
border-radius: 5px; font-weight: 700; cursor: pointer; }
button:hover { background: #4a8a9a; }
</style>
</head>
<body>
<div id="scene"></div>
<div id="controls">
<div class="big">Flugzeug-Orientierungs-Test · Bewegungsrichtung = roter Pfeil (→ weltliches +X)</div>
<div class="slider-row">
<label>rotation.x (Pitch) · <span class="val" id="val-x">0.000</span></label>
<input id="rx" type="range" min="-3.14" max="3.14" step="0.01" value="0">
</div>
<div class="slider-row">
<label>rotation.y (Yaw) · <span class="val" id="val-y">0.000</span></label>
<input id="ry" type="range" min="-3.14" max="3.14" step="0.01" value="0">
</div>
<div class="slider-row">
<label>rotation.z (Roll) · <span class="val" id="val-z">0.000</span></label>
<input id="rz" type="range" min="-3.14" max="3.14" step="0.01" value="0">
</div>
<div class="slider-row">
<button id="btn-animate">Flug simulieren</button>
<button id="btn-reset">Reset</button>
<button id="btn-copy">Werte kopieren</button>
</div>
<div class="note">
Der rote Pfeil zeigt die Bewegungsrichtung bei „Flug simulieren".<br>
Finde die rotation.y-Werte, bei denen die Nase des Flugzeugs GENAU auf dem Pfeil steht (vorwärts fliegt),
und meld mir die Werte (oder drück „Werte kopieren"). π ≈ 3.14, π/2 ≈ 1.57.
</div>
</div>
<script src="https://unpkg.com/three@0.155.0/build/three.min.js"></script>
<script>
'use strict';
// --- Scene ---
const host = document.getElementById('scene');
const scene = new THREE.Scene();
scene.background = new THREE.Color(0xbcd5e6);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setPixelRatio(Math.min(2, devicePixelRatio));
renderer.setSize(host.clientWidth, host.clientHeight);
host.appendChild(renderer.domElement);
const camera = new THREE.PerspectiveCamera(45, host.clientWidth / host.clientHeight, 0.1, 100);
camera.position.set(4, 4, 4);
camera.lookAt(0, 0, 0);
addEventListener('resize', () => {
renderer.setSize(host.clientWidth, host.clientHeight);
camera.aspect = host.clientWidth / host.clientHeight;
camera.updateProjectionMatrix();
});
// Orbit (drag)
let dragging = false, lastX = 0, lastY = 0, theta = Math.PI / 4, phi = Math.PI / 4, r = 7;
function apply() {
camera.position.set(
Math.sin(theta) * Math.sin(phi) * r,
Math.cos(phi) * r,
Math.cos(theta) * Math.sin(phi) * r
);
camera.lookAt(0, 0.3, 0);
}
apply();
renderer.domElement.addEventListener('pointerdown', (e) => { dragging = true; lastX = e.clientX; lastY = e.clientY; });
addEventListener('pointermove', (e) => {
if (!dragging) return;
theta -= (e.clientX - lastX) * 0.005;
phi = Math.max(0.1, Math.min(Math.PI * 0.48, phi - (e.clientY - lastY) * 0.005));
lastX = e.clientX; lastY = e.clientY;
apply();
});
addEventListener('pointerup', () => { dragging = false; });
renderer.domElement.addEventListener('wheel', (e) => {
e.preventDefault();
r = Math.max(2, Math.min(20, r + e.deltaY * 0.01));
apply();
}, { passive: false });
// Licht
scene.add(new THREE.AmbientLight(0xfff0d8, 0.8));
const sun = new THREE.DirectionalLight(0xffe8c0, 1.0);
sun.position.set(5, 8, 3); scene.add(sun);
// Boden-Grid
const grid = new THREE.GridHelper(20, 20, 0x808080, 0xb0b0b0);
grid.position.y = -0.5;
scene.add(grid);
// Achsen-Helper: X rot, Y grün, Z blau
const axes = new THREE.AxesHelper(1.5);
axes.position.y = -0.49;
scene.add(axes);
// Achsen-Beschriftungen (kleine Sprites)
function labelSprite(text, color) {
const c = document.createElement('canvas');
c.width = c.height = 64;
const ctx = c.getContext('2d');
ctx.font = 'bold 44px sans-serif';
ctx.fillStyle = color;
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(text, 32, 32);
const tex = new THREE.CanvasTexture(c);
const mat = new THREE.SpriteMaterial({ map: tex });
return new THREE.Sprite(mat);
}
const lx = labelSprite('+X (fwd)', '#c03030'); lx.position.set(1.8, -0.2, 0); lx.scale.set(0.8, 0.8, 1); scene.add(lx);
const ly = labelSprite('+Y (up)', '#309030'); ly.position.set(0, 1.8, 0); ly.scale.set(0.8, 0.8, 1); scene.add(ly);
const lz = labelSprite('+Z', '#3030c0'); lz.position.set(0, -0.2, 1.8); lz.scale.set(0.8, 0.8, 1); scene.add(lz);
// Großer roter Pfeil: zeigt die Bewegungsrichtung (+X)
const arrow = new THREE.ArrowHelper(
new THREE.Vector3(1, 0, 0),
new THREE.Vector3(0, -0.35, 0),
2.5,
0xd02020,
0.5, 0.3
);
scene.add(arrow);
// --- Flugzeug (genau wie in game-3d.html makePlane) ---
function makePlane() {
const g = new THREE.Group();
const bodyMat = new THREE.MeshStandardMaterial({ color: 0xe8e8ea, roughness: 0.7 });
const trimMat = new THREE.MeshStandardMaterial({ color: 0x2a4a6a, roughness: 0.8 });
const darkMat = new THREE.MeshStandardMaterial({ color: 0x1a1a1a, roughness: 1 });
const fuselage = new THREE.Mesh(
new THREE.CylinderGeometry(0.14, 0.10, 1.2, 10), bodyMat);
fuselage.rotation.z = Math.PI / 2;
g.add(fuselage);
const cockpit = new THREE.Mesh(new THREE.BoxGeometry(0.35, 0.13, 0.22), trimMat);
cockpit.position.set(0.12, 0.13, 0); g.add(cockpit);
const wing = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.04, 1.6), bodyMat);
wing.position.set(0.0, 0.20, 0); g.add(wing);
const tail = new THREE.Mesh(new THREE.BoxGeometry(0.14, 0.25, 0.04), bodyMat);
tail.position.set(-0.55, 0.25, 0); g.add(tail);
const htail = new THREE.Mesh(new THREE.BoxGeometry(0.20, 0.03, 0.5), bodyMat);
htail.position.set(-0.55, 0.18, 0); g.add(htail);
const hub = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 0.08, 8), darkMat);
hub.rotation.z = Math.PI / 2;
hub.position.set(0.62, 0, 0); g.add(hub);
const prop = new THREE.Group();
prop.position.set(0.66, 0, 0);
const blade = new THREE.Mesh(new THREE.BoxGeometry(0.01, 0.55, 0.04), darkMat);
prop.add(blade);
g.add(prop);
g.userData.propRef = prop;
for (const sx of [-0.1, 0.1]) {
const strut = new THREE.Mesh(new THREE.CylinderGeometry(0.01, 0.01, 0.15, 6), darkMat);
strut.position.set(sx, -0.14, 0); g.add(strut);
const wheel = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 0.04, 10), darkMat);
wheel.rotation.x = Math.PI / 2;
wheel.position.set(sx, -0.22, 0); g.add(wheel);
}
return g;
}
const plane = makePlane();
plane.position.set(0, 0.1, 0);
scene.add(plane);
// --- UI-Handling ---
const rx = document.getElementById('rx');
const ry = document.getElementById('ry');
const rz = document.getElementById('rz');
const vx = document.getElementById('val-x');
const vy = document.getElementById('val-y');
const vz = document.getElementById('val-z');
function updatePlane() {
plane.rotation.set(+rx.value, +ry.value, +rz.value);
vx.textContent = (+rx.value).toFixed(3);
vy.textContent = (+ry.value).toFixed(3);
vz.textContent = (+rz.value).toFixed(3);
}
[rx, ry, rz].forEach(s => s.addEventListener('input', updatePlane));
updatePlane();
document.getElementById('btn-reset').addEventListener('click', () => {
rx.value = 0; ry.value = 0; rz.value = 0;
updatePlane();
plane.position.set(0, 0.1, 0);
});
document.getElementById('btn-copy').addEventListener('click', () => {
const text = `plane.rotation.set(${(+rx.value).toFixed(3)}, ${(+ry.value).toFixed(3)}, ${(+rz.value).toFixed(3)});`;
navigator.clipboard?.writeText(text).then(() => alert('Kopiert:\n' + text)).catch(() => alert(text));
});
let animating = false, animStart = 0;
document.getElementById('btn-animate').addEventListener('click', () => {
animating = !animating;
animStart = performance.now();
plane.position.set(-3, 0.1, 0);
});
// --- Render-Loop ---
function loop() {
requestAnimationFrame(loop);
plane.userData.propRef.rotation.x += 0.3;
if (animating) {
const dt = (performance.now() - animStart) / 1000;
// Bewegung entlang +X (wie der rote Pfeil zeigt)
plane.position.x = -3 + (dt * 1.2) % 6;
}
renderer.render(scene, camera);
}
loop();
</script>
</body>
</html>
@@ -1,489 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Kachel-Test — Gebäude</title>
<style>
body { margin:0; display:flex; align-items:flex-start; justify-content:center; min-height:100vh; background:#e0e0d8; gap:10px; flex-wrap:wrap; font-family:Inter,sans-serif; padding:15px; }
.tile { display:flex; flex-direction:column; align-items:center; gap:2px; }
.tile span { font-size:9px; color:#666; }
</style>
</head>
<body>
<div class="tile"><canvas id="t01" width="200" height="200"></canvas><span>Kirche</span></div>
<div class="tile"><canvas id="t02" width="200" height="200"></canvas><span>Moschee</span></div>
<div class="tile"><canvas id="t03" width="200" height="200"></canvas><span>Wohngebiet</span></div>
<div class="tile"><canvas id="t04" width="200" height="200"></canvas><span>Fabrik</span></div>
<div class="tile"><canvas id="t05" width="200" height="200"></canvas><span>Spital</span></div>
<div class="tile"><canvas id="t06" width="200" height="200"></canvas><span>Feuerwehr</span></div>
<div class="tile"><canvas id="t07" width="200" height="200"></canvas><span>Polizei</span></div>
<div class="tile"><canvas id="t08" width="200" height="200"></canvas><span>Schule</span></div>
<div class="tile"><canvas id="t09" width="200" height="200"></canvas><span>Supermarkt</span></div>
<div class="tile"><canvas id="t10" width="200" height="200"></canvas><span>Park</span></div>
<script>
var SZ = 200
var RW = SZ * 0.4, M = SZ / 2, HR = RW / 2
var LW = 2
var GREEN = '#b8ccaa', ROAD = '#2e2e2e', WHITE = '#fff'
var DASH = [SZ*0.07, SZ*0.05]
var DOFF = -SZ*0.035
// === Strassen-Grundfunktionen ===
function base(id) {
var c = document.getElementById(id).getContext('2d')
c.fillStyle = GREEN; c.fillRect(0,0,SZ,SZ)
return c
}
function drawRoadNS(c, x) {
// Vertikale Strasse bei x-Mitte = x
c.fillStyle = ROAD; c.fillRect(x-HR, 0, RW, SZ)
c.strokeStyle = WHITE; c.lineWidth = LW
c.beginPath(); c.moveTo(x-HR,0); c.lineTo(x-HR,SZ); c.stroke()
c.beginPath(); c.moveTo(x+HR,0); c.lineTo(x+HR,SZ); c.stroke()
c.setLineDash(DASH); c.lineDashOffset = DOFF
c.beginPath(); c.moveTo(x,0); c.lineTo(x,SZ); c.stroke()
c.setLineDash([]); c.lineDashOffset = 0
}
function drawRoadEW(c, y) {
c.fillStyle = ROAD; c.fillRect(0, y-HR, SZ, RW)
c.strokeStyle = WHITE; c.lineWidth = LW
c.beginPath(); c.moveTo(0,y-HR); c.lineTo(SZ,y-HR); c.stroke()
c.beginPath(); c.moveTo(0,y+HR); c.lineTo(SZ,y+HR); c.stroke()
c.setLineDash(DASH); c.lineDashOffset = DOFF
c.beginPath(); c.moveTo(0,y); c.lineTo(SZ,y); c.stroke()
c.setLineDash([]); c.lineDashOffset = 0
}
function drawStubN(c) {
// Sackgasse von oben — kurzer Stummel
var stubY = 4
c.fillStyle = ROAD; c.fillRect(M-HR, 0, RW, stubY)
c.beginPath(); c.arc(M, stubY, HR, 0, Math.PI); c.fill()
c.strokeStyle = WHITE; c.lineWidth = LW
c.beginPath(); c.moveTo(M-HR,0); c.lineTo(M-HR,stubY); c.stroke()
c.beginPath(); c.moveTo(M+HR,0); c.lineTo(M+HR,stubY); c.stroke()
c.beginPath(); c.arc(M, stubY, HR, 0, Math.PI); c.stroke()
}
function drawStubS(c) {
var stubY = SZ - 4
c.fillStyle = ROAD; c.fillRect(M-HR, stubY, RW, 4)
c.beginPath(); c.arc(M, stubY, HR, Math.PI, 0); c.fill()
c.strokeStyle = WHITE; c.lineWidth = LW
c.beginPath(); c.moveTo(M-HR,SZ); c.lineTo(M-HR,stubY); c.stroke()
c.beginPath(); c.moveTo(M+HR,SZ); c.lineTo(M+HR,stubY); c.stroke()
c.beginPath(); c.arc(M, stubY, HR, Math.PI, 0); c.stroke()
}
function drawStubE(c) {
var stubX = SZ - 4
c.fillStyle = ROAD; c.fillRect(stubX, M-HR, 4, RW)
c.beginPath(); c.arc(stubX, M, HR, Math.PI*1.5, Math.PI*0.5); c.fill()
c.strokeStyle = WHITE; c.lineWidth = LW
c.beginPath(); c.moveTo(SZ,M-HR); c.lineTo(stubX,M-HR); c.stroke()
c.beginPath(); c.moveTo(SZ,M+HR); c.lineTo(stubX,M+HR); c.stroke()
c.beginPath(); c.arc(stubX, M, HR, Math.PI*1.5, Math.PI*0.5); c.stroke()
}
function drawStubW(c) {
var stubX = 4
c.fillStyle = ROAD; c.fillRect(0, M-HR, 4, RW)
c.beginPath(); c.arc(stubX, M, HR, Math.PI*0.5, Math.PI*1.5); c.fill()
c.strokeStyle = WHITE; c.lineWidth = LW
c.beginPath(); c.moveTo(0,M-HR); c.lineTo(stubX,M-HR); c.stroke()
c.beginPath(); c.moveTo(0,M+HR); c.lineTo(stubX,M+HR); c.stroke()
c.beginPath(); c.arc(stubX, M, HR, Math.PI*0.5, Math.PI*1.5); c.stroke()
}
// === Gebaeude-Hilfszeichnung ===
function drawBuilding(c, x, y, w, h, color, label) {
// Gebaeude als Rechteck mit Farbe + Label
c.fillStyle = color
c.fillRect(x, y, w, h)
c.strokeStyle = 'rgba(0,0,0,0.15)'; c.lineWidth = 1
c.strokeRect(x, y, w, h)
// Dach-Effekt (dunklere Oberkante)
c.fillStyle = 'rgba(0,0,0,0.08)'
c.fillRect(x, y, w, 4)
// Label
if (label) {
c.fillStyle = 'rgba(255,255,255,0.9)'
c.font = 'bold 10px Inter, sans-serif'
c.textAlign = 'center'; c.textBaseline = 'middle'
c.fillText(label, x + w/2, y + h/2)
}
}
function drawHouse(c, x, y, w, h) {
// Kleines Haus mit Dach
c.fillStyle = '#d4a574'
c.fillRect(x, y + h*0.35, w, h*0.65)
// Dach
c.fillStyle = '#8B4513'
c.beginPath()
c.moveTo(x - 2, y + h*0.35)
c.lineTo(x + w/2, y)
c.lineTo(x + w + 2, y + h*0.35)
c.closePath()
c.fill()
// Fenster
c.fillStyle = '#a8d0e0'
c.fillRect(x + w*0.2, y + h*0.5, w*0.25, h*0.2)
// Tuer
c.fillStyle = '#6a4a3a'
c.fillRect(x + w*0.55, y + h*0.55, w*0.2, h*0.4)
}
function drawTree(c, x, y, sz) {
c.fillStyle = '#5a4020'
c.fillRect(x + sz*0.4, y + sz*0.5, sz*0.2, sz*0.5)
c.fillStyle = '#3a8a2a'
c.beginPath(); c.arc(x + sz*0.5, y + sz*0.4, sz*0.4, 0, Math.PI*2); c.fill()
}
// ============================================================
// 1. KIRCHE — Sackgasse S, grosses Gebaeude
// ============================================================
;(function(){
var c = base('t01')
drawStubS(c)
// Grosses Kirchengebaeude
drawBuilding(c, 30, 15, 140, 110, '#c8b090', '')
// Turm
c.fillStyle = '#a08060'
c.fillRect(80, 5, 40, 60)
// Kreuz oben
c.strokeStyle = '#5a4a3a'; c.lineWidth = 3
c.beginPath(); c.moveTo(100, 2); c.lineTo(100, 18); c.stroke()
c.beginPath(); c.moveTo(92, 10); c.lineTo(108, 10); c.stroke()
// Tuer
c.fillStyle = '#5a3a2a'
c.beginPath(); c.arc(100, 125, 15, Math.PI, 0); c.fill()
c.fillRect(85, 115, 30, 15)
// Label
c.fillStyle = '#5a4a3a'; c.font = 'bold 11px Inter,sans-serif'; c.textAlign = 'center'
c.fillText('Kirche', 100, 85)
})()
// ============================================================
// 2. MOSCHEE — Sackgasse N + S (zwei Zufahrten)
// ============================================================
;(function(){
var c = base('t02')
drawStubN(c)
drawStubS(c)
// Gebaeude
drawBuilding(c, 25, 35, 150, 90, '#d8c8a8', '')
// Kuppel
c.fillStyle = '#c0a878'
c.beginPath(); c.arc(100, 50, 35, Math.PI, 0); c.fill()
// Halbmond
c.fillStyle = '#e8d8a0'; c.font = '18px serif'; c.textAlign = 'center'
c.fillText('☪', 100, 42)
// Minarett
c.fillStyle = '#b8a878'
c.fillRect(150, 25, 12, 70)
c.fillRect(147, 22, 18, 6)
// Label
c.fillStyle = '#6a5a3a'; c.font = 'bold 10px Inter,sans-serif'
c.fillText('Moschee', 100, 100)
})()
// ============================================================
// 3. WOHNGEBIET — Gerade N-S, Haeuser links und rechts
// ============================================================
;(function(){
var c = base('t03')
drawRoadNS(c, M)
// Haeuser links
drawHouse(c, 8, 20, 30, 30)
drawHouse(c, 12, 70, 28, 28)
drawHouse(c, 6, 120, 32, 30)
// Haeuser rechts
drawHouse(c, 160, 15, 30, 28)
drawHouse(c, 162, 65, 28, 30)
drawHouse(c, 158, 115, 32, 28)
drawHouse(c, 164, 160, 26, 26)
})()
// ============================================================
// 4. FABRIK — Kurve (N→E), Fabrik im gruenen Bereich (unten-links)
// ============================================================
;(function(){
var c = base('t04')
// Kurve N→E
var px = M+HR, py = M-HR
c.fillStyle = ROAD
c.fillRect(M-HR, 0, RW, py)
c.fillRect(px, M-HR, SZ-px, RW)
c.beginPath(); c.moveTo(px,py); c.arc(px,py,RW,Math.PI,Math.PI*0.5,true); c.closePath(); c.fill()
// Raender
c.strokeStyle=WHITE;c.lineWidth=LW
c.beginPath();c.arc(px,py,RW,Math.PI,Math.PI*0.5,true);c.stroke()
c.beginPath();c.moveTo(M+HR,0);c.lineTo(M+HR,py);c.stroke()
c.beginPath();c.moveTo(px,M-HR);c.lineTo(SZ,M-HR);c.stroke()
c.beginPath();c.moveTo(M-HR,0);c.lineTo(M-HR,py);c.stroke()
c.beginPath();c.moveTo(px,M+HR);c.lineTo(SZ,M+HR);c.stroke()
// Mittellinie
c.setLineDash(DASH);c.lineDashOffset=DOFF
c.beginPath();c.moveTo(M,0);c.lineTo(M,py);c.arc(px,py,HR,Math.PI,Math.PI*0.5,true);c.lineTo(SZ,M);c.stroke()
c.setLineDash([]);c.lineDashOffset=0
// Fabrik unten-links
drawBuilding(c, 10, 130, 70, 55, '#8a8a8a', '')
// Schornstein
c.fillStyle = '#6a6a6a'
c.fillRect(55, 110, 12, 20)
c.fillRect(30, 115, 10, 15)
// Rauch
c.fillStyle = 'rgba(100,100,100,0.25)'
c.beginPath(); c.arc(61, 105, 6, 0, Math.PI*2); c.fill()
c.beginPath(); c.arc(58, 96, 5, 0, Math.PI*2); c.fill()
// Label
c.fillStyle = '#fff'; c.font = 'bold 10px Inter,sans-serif'; c.textAlign = 'center'
c.fillText('Fabrik', 45, 160)
})()
// ============================================================
// 5. SPITAL — Sackgasse E + W (zwei Zufahrten seitlich)
// ============================================================
;(function(){
var c = base('t05')
drawStubE(c)
drawStubW(c)
// Grosses Gebaeude
drawBuilding(c, 20, 15, 160, 80, '#e8e0d0', '')
// Rotes Kreuz
c.fillStyle = '#cc3333'
c.fillRect(90, 30, 20, 50)
c.fillRect(75, 42, 50, 20)
// Label
c.fillStyle = '#6a3a3a'; c.font = 'bold 11px Inter,sans-serif'; c.textAlign = 'center'
c.fillText('Spital', 100, 120)
// Rettungswagen-Parkplatz
c.fillStyle = '#7a7a7a'; c.fillRect(30, 100, 50, 25)
c.fillStyle = '#ddd'; c.font = '16px serif'
c.fillText('🚑', 55, 117)
})()
// ============================================================
// 6. FEUERWEHR — Sackgasse S
// ============================================================
;(function(){
var c = base('t06')
drawStubS(c)
// Gebaeude
drawBuilding(c, 25, 10, 150, 100, '#cc4444', '')
// Tore (2 Garagen)
c.fillStyle = '#8a2a2a'
c.fillRect(40, 70, 45, 40)
c.fillRect(105, 70, 45, 40)
// Tor-Linien
c.strokeStyle = '#6a1a1a'; c.lineWidth = 1
for (var i = 0; i < 5; i++) { c.beginPath(); c.moveTo(40, 75+i*7); c.lineTo(85, 75+i*7); c.stroke() }
for (var i = 0; i < 5; i++) { c.beginPath(); c.moveTo(105, 75+i*7); c.lineTo(150, 75+i*7); c.stroke() }
// Label
c.fillStyle = '#fff'; c.font = 'bold 11px Inter,sans-serif'; c.textAlign = 'center'
c.fillText('Feuerwehr', 100, 45)
// Schlauchturm
c.fillStyle = '#aa3333'
c.fillRect(160, 15, 15, 55)
})()
// ============================================================
// 7. POLIZEI — Sackgasse N
// ============================================================
;(function(){
var c = base('t07')
drawStubN(c)
// Gebaeude
drawBuilding(c, 20, 50, 160, 85, '#4a6a9a', '')
// Stern/Abzeichen
c.fillStyle = '#c0d0e8'; c.font = '24px serif'; c.textAlign = 'center'
c.fillText('⭐', 100, 85)
// Label
c.fillStyle = '#fff'; c.font = 'bold 11px Inter,sans-serif'
c.fillText('Polizei', 100, 115)
// Parkplatz
c.fillStyle = '#7a7a7a'; c.fillRect(30, 145, 60, 20)
c.fillStyle = '#ddd'; c.font = '14px serif'
c.fillText('🚔', 60, 160)
})()
// ============================================================
// 8. SCHULE — Gerade E-W, Gebaeude oben
// ============================================================
;(function(){
var c = base('t08')
drawRoadEW(c, M)
// Schulgebaeude oben
drawBuilding(c, 15, 10, 170, 60, '#e0c888', '')
// Fensterreihe
c.fillStyle = '#a8d0e0'
for (var i = 0; i < 5; i++) c.fillRect(25 + i*34, 25, 22, 18)
// Label
c.fillStyle = '#5a4a2a'; c.font = 'bold 11px Inter,sans-serif'; c.textAlign = 'center'
c.fillText('Schule', 100, 58)
// Schulhof unten (Wiese ist schon gruen, ein paar Details)
drawTree(c, 30, 145, 20)
drawTree(c, 140, 150, 18)
c.fillStyle = '#aaa'; c.fillRect(70, 155, 50, 3) // Bank
})()
// ============================================================
// 9. SUPERMARKT — Gerade N-S, Gebaeude rechts mit Parkplatz
// ============================================================
;(function(){
var c = base('t09')
drawRoadNS(c, M)
// Supermarkt rechts
drawBuilding(c, 140, 20, 55, 80, '#e0d0a0', '')
// Label
c.fillStyle = '#5a4a2a'; c.font = 'bold 9px Inter,sans-serif'; c.textAlign = 'center'
c.fillText('Super-', 167, 50)
c.fillText('markt', 167, 62)
// Parkplatz
c.fillStyle = '#8a8a8a'
c.fillRect(140, 110, 55, 40)
// Parkplatz-Linien
c.strokeStyle = '#aaa'; c.lineWidth = 1
for (var i = 0; i < 4; i++) { c.beginPath(); c.moveTo(152+i*12, 110); c.lineTo(152+i*12, 150); c.stroke() }
// Einkaufswagen
c.fillStyle = '#ddd'; c.font = '12px serif'
c.fillText('🛒', 167, 135)
})()
// ============================================================
// 10. PARK — Sackgasse N, viel Gruen
// ============================================================
;(function(){
var c = base('t10')
drawStubN(c)
// Baeume
drawTree(c, 15, 40, 28)
drawTree(c, 60, 55, 24)
drawTree(c, 130, 35, 30)
drawTree(c, 155, 80, 22)
drawTree(c, 25, 120, 26)
drawTree(c, 100, 110, 20)
drawTree(c, 150, 140, 24)
// Teich
c.fillStyle = 'rgba(60,140,200,0.4)'
c.beginPath(); c.ellipse(80, 140, 30, 18, 0.1, 0, Math.PI*2); c.fill()
c.strokeStyle = 'rgba(60,140,200,0.3)'; c.lineWidth = 1; c.stroke()
// Bank
c.fillStyle = '#8a7050'
c.fillRect(95, 82, 20, 6)
c.fillRect(95, 82, 3, 10)
c.fillRect(112, 82, 3, 10)
// Weg (kleiner Pfad)
c.strokeStyle = 'rgba(160,140,100,0.4)'; c.lineWidth = 3; c.setLineDash([4,3])
c.beginPath(); c.moveTo(M, 10); c.quadraticCurveTo(60, 80, 80, 140); c.stroke()
c.setLineDash([])
// Label
c.fillStyle = 'rgba(0,0,0,0.35)'; c.font = 'bold 11px Inter,sans-serif'; c.textAlign = 'center'
c.fillText('Park', 100, 175)
})()
// ============================================================
// EMOJI-VERSIONEN (Gegenversuch)
// ============================================================
var emojiTiles = [
{id:'e01', label:'Kirche', stub:'S', emoji:'⛪', size:95},
{id:'e02', label:'Moschee', stub:'NS', emoji:'🕌', size:85},
{id:'e03', label:'Wohngebiet', road:'NS', emojis:[
{e:'🏠',x:-0.32,y:-0.3,s:32},{e:'🏡',x:-0.3,y:0,s:30},{e:'🏠',x:-0.32,y:0.28,s:28},
{e:'🏘️',x:0.32,y:-0.25,s:30},{e:'🏠',x:0.3,y:0.05,s:32},{e:'🏡',x:0.32,y:0.3,s:28}]},
{id:'e04', label:'Fabrik', stub:'S', emoji:'🏭', size:85},
{id:'e05', label:'Spital', stub:'EW', emoji:'🏥', size:65, yoff:-0.12, extra:[{e:'🚑',x:0,y:0.3,s:30}]},
{id:'e06', label:'Feuerwehr', stub:'S', bg:'rgba(200,50,40,0.12)', emojis:[
{e:'🏠',x:0,y:-0.15,s:60},{e:'🚒',x:-0.2,y:0.22,s:40},{e:'🚒',x:0.2,y:0.22,s:40}]},
{id:'e07', label:'Polizei', stub:'N', emoji:'🚔', size:45, extra:[{e:'🏢',x:0,y:0.15,s:55}]},
{id:'e08', label:'Schule', road:'EW', emoji:'🏫', size:60, yoff:-0.28},
{id:'e09', label:'Supermarkt', road:'NS', emoji:'🏪', size:55, xoff:0.3, extra:[
{e:'🚗',x:0.22,y:0.25,s:26},{e:'🚙',x:0.35,y:0.15,s:24},{e:'🚗',x:0.22,y:0.38,s:22}]},
{id:'e10', label:'Park', stub:'N', emojis:[
{e:'🌳',x:-0.3,y:-0.1,s:32},{e:'🌳',x:-0.1,y:-0.1,s:32},{e:'🌳',x:0.1,y:-0.1,s:32},{e:'🌳',x:0.3,y:-0.1,s:32},
{e:'🌳',x:-0.2,y:0.1,s:28},{e:'🌳',x:0,y:0.1,s:28},{e:'🌳',x:0.2,y:0.1,s:28},
{e:'🌷',x:-0.35,y:0.3,s:16},{e:'🌷',x:-0.2,y:0.32,s:14},{e:'🌷',x:-0.05,y:0.3,s:16},
{e:'🌷',x:0.1,y:0.32,s:14},{e:'🌷',x:0.25,y:0.3,s:16},{e:'🌷',x:0.38,y:0.32,s:14}]},
{id:'e11', label:'Rathaus', stub:'S', emoji:'🏛️', size:85},
{id:'e13', label:'Tankstelle', road:'NS', emojis:[
{e:'⛽',x:0.28,y:-0.2,s:32},{e:'⛽',x:0.28,y:0,s:32},{e:'⛽',x:0.28,y:0.2,s:32},
{e:'🚗',x:0.38,y:-0.15,s:26},{e:'🚙',x:0.38,y:0.15,s:26}]},
{id:'e14', label:'Spielplatz', stub:'N', emojis:[
{e:'🛝',x:-0.2,y:0,s:42},{e:'🎠',x:0.2,y:0,s:36},{e:'⚽',x:0,y:0.25,s:22},
{e:'🌳',x:-0.35,y:0.3,s:26},{e:'🌳',x:0.35,y:0.3,s:26}]},
{id:'e15', label:'Bauernhof', stub:'EW', emojis:[
{e:'🏠',x:0,y:-0.05,s:55},
{e:'🌾',x:-0.35,y:-0.3,s:24},{e:'🌾',x:-0.2,y:-0.3,s:24},{e:'🌾',x:-0.05,y:-0.3,s:24},
{e:'🌾',x:0.1,y:-0.3,s:24},{e:'🌾',x:0.25,y:-0.3,s:24},{e:'🌾',x:0.4,y:-0.3,s:24},
{e:'🐄',x:-0.25,y:0.28,s:30},{e:'🐔',x:0.15,y:0.3,s:22},{e:'🐔',x:0.28,y:0.28,s:22}]},
{id:'e16', label:'Hochhäuser', road:'NS', emojis:[
{e:'🏢',x:0.22,y:-0.2,s:38},{e:'🏢',x:0.32,y:-0.2,s:38},{e:'🏢',x:0.42,y:-0.2,s:38},
{e:'🏢',x:0.22,y:0.15,s:38},{e:'🏢',x:0.32,y:0.15,s:38},{e:'🏢',x:0.42,y:0.15,s:38}]},
]
// Erzeuge HTML fuer Emoji-Tiles
var hr = document.createElement('div')
hr.style.cssText = 'width:100%;text-align:center;color:#888;font-size:11px;margin:8px 0;border-top:1px solid #ccc;padding-top:6px'
hr.textContent = '▼ Emoji-Versionen ▼'
document.body.appendChild(hr)
emojiTiles.forEach(function(t) {
var div = document.createElement('div')
div.className = 'tile'
var cv = document.createElement('canvas')
cv.width = 200; cv.height = 200; cv.id = t.id
var span = document.createElement('span')
span.textContent = t.label
div.appendChild(cv); div.appendChild(span)
document.body.appendChild(div)
var c = cv.getContext('2d')
c.fillStyle = GREEN; c.fillRect(0, 0, SZ, SZ)
// Hintergrundfarbe (z.B. rot fuer Feuerwehr)
if (t.bg) { c.fillStyle = t.bg; c.fillRect(0, 0, SZ, SZ) }
// Strasse
if (t.road === 'NS') drawRoadNS(c, M)
if (t.road === 'EW') drawRoadEW(c, M)
if (t.stub) {
if (t.stub.indexOf('N') >= 0) drawStubN(c)
if (t.stub.indexOf('S') >= 0) drawStubS(c)
if (t.stub.indexOf('E') >= 0) drawStubE(c)
if (t.stub.indexOf('W') >= 0) drawStubW(c)
}
// Emojis
c.textAlign = 'center'; c.textBaseline = 'middle'
if (t.emoji) {
c.font = (t.size || 50) + 'px serif'
c.fillText(t.emoji, M + (t.xoff || 0) * SZ, M + (t.yoff || 0) * SZ)
}
if (t.emojis) {
t.emojis.forEach(function(em) {
c.font = (em.s || 24) + 'px serif'
c.fillText(em.e, M + em.x * SZ, M + em.y * SZ)
})
}
if (t.extra) {
t.extra.forEach(function(em) {
c.font = (em.s || 24) + 'px serif'
c.fillText(em.e, M + (em.x||0) * SZ, M + (em.y||0) * SZ)
})
}
// Keine Beschriftung auf der Kachel
})
</script>
</body>
</html>
@@ -1,496 +0,0 @@
{
"country": "AT",
"recherche_datum": "2026-06-08",
"researcher_notes": [
"Quellen direkt aus RIS (Rechtsinformationssystem des Bundes) per WebFetch + pdftotext extrahiert.",
"Wörtliche Zitate aus PDF (BGBl. II Nr. 1/2023). Umlaute aus Layout-Extraktion teils als 'a/o/u' korrigiert (ä, ö, ü, ß, ) — der semantische Inhalt ist identisch zur Quelle.",
"Alle Zitate ≤ 500 Zeichen.",
"Lehrplan-Verordnung 'Lehrpläne der Mittelschulen' (Gesetzesnummer 20007850) gilt für MS und ist inhaltlich für AHS-Unterstufe (Gesetzesnummer 10008568) parallel formuliert; daher MS+AHS-U.",
"Plattform-Kompetenz-Slug 'neu:<name>' kennzeichnet Vorschläge, die noch nicht in der DB existieren.",
"Sim-Liste (zur Auswahl): klima, klima-3d, fluss, heli, energiemanager, eu-werkstatt, farmer, busfahrt, sonnensystem, logistik, weltkueche."
],
"quellen": [
{
"name": "BMBWF Lehrpläne der Mittelschulen — Anlage 1 (Verordnung BGBl. II Nr. 1/2023)",
"url": "https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=20007850",
"pdf_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"version_datum": "2023-01-02",
"ausgegeben": "BGBl. II — Ausgegeben am 2. Jänner 2023 — Nr. 1",
"geltend_seit": "Aufsteigend in Kraft ab 2023-09-01 (1. Klasse), 2024-09-01 (2. Kl.), 2025-09-01 (3. Kl.), 2026-09-01 (4. Kl.)"
},
{
"name": "BMBWF Lehrpläne der allgemeinbildenden höheren Schulen — Anlage A (Verordnung BGBl. II Nr. 1/2023)",
"url": "https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10008568",
"pdf_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0012_E1BFECE6_7E8B_4ACF_AEFD_3EC871222138.pdfsig",
"version_datum": "2023-01-02",
"anmerkung": "Fachlehrpläne GW, BU, EH, GPB der AHS-Unterstufe sind inhaltlich identisch zur Mittelschulfassung; Zitate hier aus MS-Fassung übernommen — gelten parallel für AHS-U (Unterstufe). PDF wurde aufgrund Größe nicht separat extrahiert."
},
{
"name": "BMBWF Lehrplan der Volksschule — Anlage 1 (Verordnung BGBl. II Nr. 1/2023)",
"url": "https://www.ris.bka.gv.at/GeltendeFassung.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10009275",
"pdf_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0001_CE7F0AA2_A925_4A4D_8C3C_355D12BD22D1.pdfsig",
"version_datum": "2023-01-02",
"ausgegeben": "BGBl. II — Ausgegeben am 2. Jänner 2023 — Nr. 1"
}
],
"kompetenzen": [
{
"code": "GW Kompetenzbereich 1.3 — Leben und Wirtschaften im Hinblick auf nachhaltige Ernährung",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "1. Klasse Sek I",
"title": "Landwirtschaft, Ernährungssysteme und Klimawandel — Welternährung",
"quote": "Die Schülerinnen und Schüler können ausgehend von individuellen Ernährungsgewohnheiten (land)wirtschaftliche Produktion, deren gesellschaftliche, wirtschaftliche und naturräumliche Bedingungen sowie deren Wandel an weltweit ausgewählten Fallbeispielen verorten und vergleichen; … den Einfluss des Klimawandels auf die Erzeugung von ausreichenden und gesunden Nahrungsmitteln an Fallbeispielen erörtern.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "103 von 151 (Anlage 1, BGBl. II 1/2023)",
"passende_sims": ["weltkueche", "farmer", "klima", "klima-3d", "busfahrt"],
"passende_plattform_kompetenzen": ["landwirtschaft-klimazonen", "klimawandel"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "Welternährung, Landwirtschaft global, Klimawandel-Auswirkung auf Lebensmittelerzeugung"
},
{
"code": "GW Kompetenzbereich 1.4 — Leben und Wirtschaften unter Beachtung der natürlichen Prozesse",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "1. Klasse Sek I",
"title": "Naturgefahren, Wechselwirkung Natur/Wirtschaft, solidarisches Handeln",
"quote": "Die Schülerinnen und Schüler können Wechselwirkungen von Naturereignissen, Lebensqualität und Wirtschaften der Menschen anhand von Fallbeispielen beschreiben und erörtern; unterschiedliche Betroffenheit von Menschen und Gesellschaften durch Naturgefahren in angemessener Sprache bewerten und Möglichkeiten solidarischen Handelns erörtern.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "103 von 151",
"passende_sims": ["fluss", "heli", "klima", "klima-3d"],
"passende_plattform_kompetenzen": ["naturgefahren-hochwasser", "klimawandel"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "GW Kompetenzbereich 2.1 — Nachhaltiger Umgang mit Energie und Ressourcen",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "2. Klasse Sek I",
"title": "Erneuerbare vs. nicht erneuerbare Energieträger, Klimawandel, Ressourcenverteilung",
"quote": "Die Schülerinnen und Schüler können die Nutzung erneuerbarer und nicht erneuerbarer Energieträger vergleichen und aus den Blickwinkeln von Klimawandel und Nachhaltigkeit reflektieren; die ungleiche räumliche und gesellschaftliche Verteilung von Ressourcen mit Hilfe von (Geo-)Medien beschreiben und deren Nutzung, Wiederverwendung und Entsorgung analysieren; den verantwortungsvollen Umgang mit den natürlichen Ressourcen wie Wasser, Luft oder Boden erörtern …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "103104 von 151",
"passende_sims": ["energiemanager", "klima", "klima-3d", "farmer"],
"passende_plattform_kompetenzen": ["energieversorgung-speicherung", "klimawandel"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "GW Kompetenzbereich 2.2 — Vernetztes Wirtschaften zwischen Produktion und Konsum",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "2. Klasse Sek I",
"title": "Märkte, Angebot/Nachfrage, Preisbildung, arbeitsteilige Produktion",
"quote": "Die Schülerinnen und Schüler können … arbeitsteiliges und spezialisiertes Produzieren von Gütern und Anbieten von Dienstleistungen sowie das freie Treffen von Produktionsentscheidungen durch Haushalte, Unternehmen und Staat beschreiben; … das Zusammentreffen von Angebot und Nachfrage nach verschiedenen Gütern (einschließlich Leistungen) auf Märkten (Güter-, Arbeits-, und Kapitalmärkte) sowie deren wesentliche Funktionen insbesondere für die Preisbildung charakterisieren …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "104 von 151",
"passende_sims": ["logistik", "busfahrt", "farmer", "weltkueche"],
"passende_plattform_kompetenzen": ["wirtschaft-logistikverstaendnis", "planungs-entscheidungskompetenz"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "GW Kompetenzbereich 3.3 — Entwicklungen am Wirtschaftsstandort Österreich (Außenwirtschaftliche Verflechtungen)",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "3. Klasse Sek I",
"title": "Import/Export — Außenwirtschaft Österreichs mit EU und Welt",
"quote": "Die Schülerinnen und Schüler können … Gründe, Bedeutung sowie ökonomische, gesellschaftliche und ökologische Folgen der außenwirtschaftlichen Verflechtungen (Import/Export) Österreichs mit der EU und der restlichen Welt erläutern.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "105 von 151",
"passende_sims": ["logistik", "busfahrt", "weltkueche", "eu-werkstatt"],
"passende_plattform_kompetenzen": ["wirtschaft-logistikverstaendnis", "eu-politische-beteiligung"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "Welthandel — Import/Export Österreichs explizit benannt"
},
{
"code": "GW Kompetenzbereich 3.4 — Zentren und Peripherien in Österreich",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "3. Klasse Sek I",
"title": "Raumnutzung, Raumplanung, Nutzungskonflikte",
"quote": "Die Schülerinnen und Schüler können Zentren und Peripherien Österreichs abgrenzen, in Geomedien verorten und die Relativität jeder Abgrenzung erläutern; … mit Hilfe von (Geo-)Medien die Raumnutzungen für Wohnen, Arbeit, Verkehr, Freizeitaktivitäten und Tourismus vergleichen sowie Lösungsansätze der Raumplanung bei Nutzungskonflikten erörtern.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "105 von 151",
"passende_sims": ["fluss", "logistik", "busfahrt"],
"passende_plattform_kompetenzen": ["stadtplanung-raum", "raeumliche-orientierung-europa"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "GW Kompetenzbereich 4.1 — Mensch und Natursysteme",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "4. Klasse Sek I",
"title": "Anthropozän, Belastungsgrenzen, Klimawandel, Artensterben",
"quote": "Die Schülerinnen und Schüler können das Ausmaß des menschlichen Einflusses auf Natursysteme anhand von Beispielen wie Einbringung von Schadstoffen, Land- und Ressourcennutzung … beschreiben; Folgen der Überschreitung von Belastungsgrenzen der Erde, des Klimawandels oder des Artensterbens auf das Leben und Wirtschaften erörtern; über das sich wandelnde Verhältnis zwischen Mensch und Natur reflektieren …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "105106 von 151",
"passende_sims": ["klima", "klima-3d", "farmer", "weltkueche"],
"passende_plattform_kompetenzen": ["klimawandel", "landwirtschaft-klimazonen"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "GW Kompetenzbereich 4.2 — Europa und europäische Integration",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "4. Klasse Sek I",
"title": "EU — vier Grundfreiheiten, Euro, gemeinsame Werte",
"quote": "Die Schülerinnen und Schüler können unterschiedliche Gliederungen, Wahrnehmungen und Darstellungen von Europa und der Europäischen Union in ihrer Vielfalt beschreiben, in (Geo-)Medien analysieren … die Bedeutung gemeinsamer Werte wie Friedenserhaltung, Demokratie oder Freiheit begründen und zentrale Themen der EU wie die vier Grundfreiheiten (Waren, Personen, Kapital und Dienstleistungen), den Euro, Bildungskooperationen, Qualitätsstandards, Verbraucherschutz oder Regionalentwicklung … reflektieren …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "106 von 151",
"passende_sims": ["eu-werkstatt", "logistik", "busfahrt"],
"passende_plattform_kompetenzen": ["eu-politische-beteiligung", "raeumliche-orientierung-europa"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "EU-Politik / EU-Institutionen / Vier Grundfreiheiten / Euro / Verbraucherschutz"
},
{
"code": "GW Kompetenzbereich 4.3 — Entwicklungen in einer globalisierten Welt",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "4. Klasse Sek I",
"title": "Globalisierung, Lieferketten, Klimawandel, Migration",
"quote": "Die Schülerinnen und Sch[ülerinnen] können … Möglichkeiten und Grenzen der Zusammenarbeit sowie den Wandel der Machtverhältnisse zwischen Staaten, Bündnissen, NGOs, Konzernen, internationalen Organisationen und Bewegungen untersuchen und darstellen; Elemente, Anforderungen und Herausforderungen nachhaltiger wirtschaftlicher Aktivitäten und Beziehungen in der globalisierten Welt diskutieren zB vor dem Hintergrund von Klimawandel, Ressourcenknappheit, Armut und Wohlstand, Flucht und Migration …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "106 von 151",
"passende_sims": ["weltkueche", "logistik", "busfahrt", "farmer", "klima", "klima-3d"],
"passende_plattform_kompetenzen": ["wirtschaft-logistikverstaendnis", "klimawandel", "systemisches-denken"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "Globalisierung, Welthandel, internationale Konzerne, NGOs"
},
{
"code": "GW Anwendungsbereiche 4. Klasse — Mensch-Umwelt-Verhältnis im Anthropozän",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "4. Klasse Sek I",
"title": "Anwendungsbereiche Welthandel/Globalisierung/EU",
"quote": "Anwendungsbereiche: Mensch-Umweltverhältnis im Anthropozän; Belastungsgrenzen der Erde; Werte und zentrale Themen der EU; Europäische Integration einschließlich gesellschaftliche und wirtschaftliche Folgen; Globale Bevölkerungsdynamik, Urbanisierung; Wirtschaftlicher und gesellschaftlicher Wandel durch Globalisierung und Deglobalisierung; Gemeinsame Herausforderungen in Gesellschaft, Wirtschaft, Politik und Umwelt; Eigene Chancen und Perspektiven in einer globalisierten Welt.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "106 von 151",
"passende_sims": ["eu-werkstatt", "weltkueche", "logistik", "busfahrt", "klima", "klima-3d"],
"passende_plattform_kompetenzen": ["eu-politische-beteiligung", "klimawandel", "wirtschaft-logistikverstaendnis"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "GW Didaktische Grundsätze — Maßstabsebenen und Geomedien",
"subject": "Geografie und wirtschaftliche Bildung",
"school_type": "MS / AHS-U",
"grade": "1.4. Klasse Sek I",
"title": "Räumliche Maßstabsebenen — persönlich/lokal/regional/national/global",
"quote": "Alle Zielsetzungen und Inhalte sollen daher im Wirkungsgefüge „Gesellschaft Wirtschaft Politik Umwelt“ bearbeitet werden. Dabei sollen bildungsrelevante Fallbeispiele mit Problembezug auf unterschiedlichen Maßstabsebenen (persönlich, lokal, regional, national und global) erarbeitet werden. … Medien, insbesondere Geomedien (das sind digitale und analoge Medien mit ortsbezogenen Daten), werden zum Erschließen, Produzieren und Kommunizieren von geografischen und wirtschaftlichen Inhalten eingesetzt.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "100101 von 151",
"passende_sims": ["heli", "logistik", "busfahrt", "sonnensystem"],
"passende_plattform_kompetenzen": ["karten-navigation-alpen", "kartenkompetenz-logistik", "raeumliche-orientierung-europa"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "EH Kompetenzbereich 1 — Ernährung, Gesundheit und Soziales (2. Klasse)",
"subject": "Ernährung und Haushalt",
"school_type": "MS / AHS-U",
"grade": "2. Klasse Sek I (Pflichtfach MS; AHS-U als verbindliche Übung/Wahlpflicht je Standort)",
"title": "Bedarfsgerechte Ernährung, Lebensmittelqualität, ressourcenschonende Zubereitung",
"quote": "Die Schülerinnen und Schüler können Einflüsse auf Ernährungsgewohnheiten (ua. kulturelle, religiöse, soziale und geografische) reflektieren; die Grundlagen bedarfsgerechter Ernährung benennen und das eigene Ess- und Trinkverhalten bewerten; Lebensmittel und deren Qualität nach differenzierten Aspekten beurteilen; grundlegende Techniken der Nahrungszubereitung gesundheitsorientiert und ressourcenschonend anwenden; Ernährungsentscheidungen qualitäts- und genussorientiert treffen und begründen.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "132 von 151",
"passende_sims": ["weltkueche", "farmer"],
"passende_plattform_kompetenzen": ["landwirtschaft-klimazonen", "neu:ernaehrungs-und-konsumkompetenz"],
"neu_oder_vorhanden": "neu",
"luecke_geschlossen": "Welternährung, Lebensmittelqualität, kulturelle/geografische Ernährungseinflüsse"
},
{
"code": "EH Anwendungsbereiche Kompetenzbereich 2 — Regionale/saisonale Lebensmittel, globale Produktion",
"subject": "Ernährung und Haushalt",
"school_type": "MS / AHS-U",
"grade": "2. Klasse Sek I",
"title": "Regional, saisonal, globale Produktionsketten, Nachhaltigkeit",
"quote": "Anwendungsbereiche: Regionale und saisonale Lebensmittelauswahl; Globale und lokale Zusammenhänge der Produktion von Gütern; Analyse von Produkten in Hinblick auf Nachhaltigkeit und Gesundheit Produktlinienanalyse; Arbeits- und Alltagsorganisation im privaten Haushalt; Haushaltsbudget, Kaufentscheidungen, Nutzung und Reklamation.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "132133 von 151",
"passende_sims": ["weltkueche", "farmer", "logistik"],
"passende_plattform_kompetenzen": ["landwirtschaft-klimazonen", "wirtschaft-logistikverstaendnis", "neu:ernaehrungs-und-konsumkompetenz"],
"neu_oder_vorhanden": "neu",
"luecke_geschlossen": "Saisonal/regional, globale Lebensmittel-Produktionsketten — direkt im Lehrplan benannt"
},
{
"code": "EH Zentrale Konzepte — Ernährung des Menschen / Nachhaltigkeit / Haushalt",
"subject": "Ernährung und Haushalt",
"school_type": "MS / AHS-U",
"grade": "2. Klasse Sek I",
"title": "Ernährung individuell/sozial/global; Nachhaltigkeit Ökologie/Ökonomie/Soziales",
"quote": "Ernährung des Menschen: … Der Anspruch an die Ernährung des Menschen liegt darin, dass sie gleichermaßen bedarfsgerecht, gesundheitsfördernd, genussvoll sowie nachhaltig sein soll. Der Fokus richtet sich auf den individuellen, sozialen und globalen Kontext. … Nachhaltigkeit: Das Wirkungsgefüge von Ökologie, Ökonomie und Sozialem sowie deren Wechselbeziehungen spiegelt sich im Konzept der Nachhaltigkeit.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "131132 von 151",
"passende_sims": ["weltkueche", "farmer", "klima", "klima-3d"],
"passende_plattform_kompetenzen": ["landwirtschaft-klimazonen", "klimawandel", "neu:ernaehrungs-und-konsumkompetenz"],
"neu_oder_vorhanden": "neu"
},
{
"code": "BU Anwendungsbereiche 1. Klasse — Bestäubung und Befruchtung",
"subject": "Biologie und Umweltbildung",
"school_type": "MS / AHS-U",
"grade": "1. Klasse Sek I",
"title": "Bestäubung als Funktion der Blüte",
"quote": "Anwendungsbereiche 1. Klasse: Wechselbeziehungen zwischen Lebewesen in ihrem Lebensraum; Vielfalt und Angepasstheit sowie Grundzüge der Systematik von Blütenpflanzen; Bestäubung und Befruchtung als Funktionen der Blüte; Gemeinsamkeiten von Wirbeltieren, die auf deren Verwandtschaft hinweisen; …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "91 von 151",
"passende_sims": ["farmer", "weltkueche"],
"passende_plattform_kompetenzen": ["landwirtschaft-klimazonen"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "Bestäubung als expliziter Lehrplan-Inhalt (BU 1. Kl.)"
},
{
"code": "BU Anwendungsbereiche 4. Klasse — Konventionelle vs. biologische Landwirtschaft; Klimawandel",
"subject": "Biologie und Umweltbildung",
"school_type": "MS / AHS-U",
"grade": "4. Klasse Sek I",
"title": "Landwirtschaft, Biodiversität, anthropogene Einflüsse, CO2 und Klimawandel",
"quote": "Anwendungsbereiche 4. Klasse: Ökologische Zusammenhänge, Biodiversität und anthropogene Einflüsse im Bereich der Landwirtschaft, Charakteristika der konventionellen und der biologischen Landwirtschaft; Ökologische Zusammenhänge, Biodiversität und anthropogene Einflüsse in Siedlungsräumen, Pflanzen und Tiere als Kulturfolger, Vermeidung von Müll und Lebensmittelverschwendung; Globaler Kohlenstoffkreislauf, CO2-Eintrag in die Atmosphäre, Klimawandel; …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "9192 von 151",
"passende_sims": ["farmer", "klima", "klima-3d", "weltkueche"],
"passende_plattform_kompetenzen": ["landwirtschaft-klimazonen", "klimawandel"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "Konventionelle vs. biologische Landwirtschaft, Monokultur-Bezug, Lebensmittelverschwendung, CO2-Kreislauf"
},
{
"code": "BU Anwendungsbereiche 3. Klasse — Gesteinskreislauf und Plattentektonik",
"subject": "Biologie und Umweltbildung",
"school_type": "MS / AHS-U",
"grade": "3. Klasse Sek I",
"title": "Plattentektonik und Lebensräume",
"quote": "Anwendungsbereiche 3. Klasse: … Gesteinskreislauf und Plattentektonik, Zusammenhänge zwischen Geologie und Lebensräumen; Funktion von Mikroorganismen im Boden, Bedeutung des Bodens für die Pflanzen, anthropogene Einflüsse auf den Boden; Entstehung von Fossilien und Geschichte des Lebens auf der Erde; …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "91 von 151",
"passende_sims": ["sonnensystem", "fluss", "farmer"],
"passende_plattform_kompetenzen": ["erdmechanik-klimazonen", "naturgefahren-hochwasser"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "GPB Anwendungsbereich 4. Klasse — Europäisierung / EU als Wirtschafts- und Friedensprojekt",
"subject": "Geschichte und Politische Bildung",
"school_type": "MS / AHS-U",
"grade": "4. Klasse Sek I",
"title": "EU-Beitritt Österreichs, Europa als Friedens-/Wirtschaftsprojekt",
"quote": "Europäisierung (unterschiedliche historische und gegenwärtige Konzeptionen von Europa; die EU als Wirtschafts- und Friedensprojekt; Ende des geteilten Europas 1989 und die Auswirkungen; Beitritt Österreichs zur EU und die nachfolgenden Veränderungen in Außen-, Sicherheits- und Neutralitätspolitik, in Gesellschaft und Alltag; Einfluss der EU auf die Lebenswelt der Schülerinnen und Schüler).",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "99 von 151",
"passende_sims": ["eu-werkstatt", "busfahrt"],
"passende_plattform_kompetenzen": ["eu-politische-beteiligung"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "GPB Anwendungsbereich 4. Klasse — Politische Mitbestimmung in Gegenwart und Zukunft",
"subject": "Geschichte und Politische Bildung",
"school_type": "MS / AHS-U",
"grade": "4. Klasse Sek I",
"title": "Politische Institutionen, Bürgerbeteiligung, Föderalismus, NGOs",
"quote": "Politische Mitbestimmung in Gegenwart und Zukunft (demokratische Werte und Grundrechte; Menschenrechte; Minderheitenrechte; Räume, Möglichkeiten und Strategien: politische Institutionen, außerparlamentarische Formen der Mitbestimmung … Aktionen von Bürgerinnen und Bürgern im öffentlichen Raum; Machtungleichheiten in politischen Prozessen, Opposition und Regierung, NGOs); Aufgaben und Kompetenzverteilung von Gemeinden, Ländern und Bund bundesstaatliches Prinzip/Föderalismus …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "99 von 151",
"passende_sims": ["eu-werkstatt"],
"passende_plattform_kompetenzen": ["eu-politische-beteiligung"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "GPB Anwendungsbereich 4. Klasse — Aspekte von Globalisierung",
"subject": "Geschichte und Politische Bildung",
"school_type": "MS / AHS-U",
"grade": "4. Klasse Sek I",
"title": "Globalisierung, weltweite Vernetzung, ökologische Herausforderungen",
"quote": "Aspekte von Globalisierung im 20. und 21. Jahrhundert (Friedenssicherung nach 1945 und welt- und wirtschaftspolitische Machtblöcke in globaler Perspektive, „Kalter Krieg“; politische, ökonomische und gesellschaftliche Phänomene der Globalisierung ua. Urbanisierung, ökologische Herausforderungen; weltweit sich vernetzende Phänomene ua. Konsum, Popkultur, Internet/digitale Medien, Seuchen); Befreiungsbewegungen im Globalen Süden …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "9899 von 151",
"passende_sims": ["weltkueche", "logistik", "busfahrt"],
"passende_plattform_kompetenzen": ["wirtschaft-logistikverstaendnis", "systemisches-denken"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "Globalisierung — historisch/politisch verankert"
},
{
"code": "Übergreifendes Thema 11 — Umweltbildung für nachhaltige Entwicklung (Kompetenzziele Sek I)",
"subject": "Umweltbildung für nachhaltige Entwicklung",
"school_type": "MS / AHS-U",
"grade": "Ende Sek I (übergreifend)",
"title": "BNE — Klimawandel, Ressourcen, Biodiversität, nachhaltiger Konsum",
"quote": "Die Schülerinnen und Schüler können das Zusammenwirken von ökologischen, ökonomischen und sozialen Faktoren bei Umweltproblemen verstehen und mögliche Lösungsvorschläge ableiten; die Bedeutung des Einsatzes ressourcen- und umweltschonender sowie sozial verantwortlicher Verfahren, Produkte und Dienstleistungen in Beruf und Wirtschaft erkennen … die eigenen Lebensgewohnheiten auf Prinzipien der Nachhaltigkeit überprüfen … Visionen für eine umweltverträgliche und nachhaltige Zukunft entwickeln …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "1516 von 151",
"passende_sims": ["klima", "klima-3d", "energiemanager", "farmer", "weltkueche", "fluss"],
"passende_plattform_kompetenzen": ["klimawandel", "landwirtschaft-klimazonen", "energieversorgung-speicherung"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "Übergreifendes Thema 11 — UBNE Kernthemen (Bedeutung)",
"subject": "Umweltbildung für nachhaltige Entwicklung",
"school_type": "MS / AHS-U",
"grade": "1.4. Klasse Sek I",
"title": "Kernthemen BNE — Klimawandel, Lebensraumschutz, Lebensmittelabfälle, Recycling",
"quote": "Als Kernthemen werden ua. Artenvielfalt und -schutz; Klimawandel und -schutz; Lebensräume und deren Vernetzung und Schutz von Boden, Wasser, Luft, Wäldern und Meeren; nachhaltige und sozial gerechte Ressourcen- und Energienutzung; Vermeidung von Lebensmittelabfällen, Abfall und Emissionen; Recycling; Ernährung und verantwortungsvoller Konsum gesehen.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "15 von 151",
"passende_sims": ["farmer", "weltkueche", "klima", "klima-3d", "energiemanager", "fluss"],
"passende_plattform_kompetenzen": ["klimawandel", "landwirtschaft-klimazonen", "energieversorgung-speicherung"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "Lebensmittelverschwendung, verantwortungsvoller Konsum"
},
{
"code": "Übergreifendes Thema 12 — Verkehrs- und Mobilitätsbildung (Kompetenzziele Sek I)",
"subject": "Verkehrs- und Mobilitätsbildung",
"school_type": "MS / AHS-U",
"grade": "Ende Sek I (übergreifend)",
"title": "Klimafreundliche Mobilität, Verkehrssystem, Sicherheit",
"quote": "Die Schülerinnen und Schüler können Verkehrsvorschriften erklären und einhalten; Kriterien für ein unfallfreies Miteinander im Verkehr beschreiben und bei der Teilnahme am Verkehr vorausschauend und verkehrsgerecht … handeln; … Auswirkungen der Mobilität auf die Umwelt beschreiben, das eigene Mobilitätsverhalten reflektieren und eine umweltbewusste Werthaltung einnehmen; Kriterien für ein zukunftsfähiges, nachhaltiges Verkehrssystem benennen und für das eigene Umfeld reflektieren.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "1516 von 151",
"passende_sims": ["busfahrt", "logistik", "heli"],
"passende_plattform_kompetenzen": ["verkehrserziehung-sicherheit", "systemisches-denken"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "Übergreifendes Thema 13 — Wirtschafts-, Finanz- und Verbraucher:innenbildung (Kompetenzziele Sek I)",
"subject": "Wirtschafts-, Finanz- und Verbraucher:innenbildung",
"school_type": "MS / AHS-U",
"grade": "Ende Sek I (übergreifend)",
"title": "Verantwortlicher Geld-/Konsumumgang, Wirtschaftskreislauf, Verbraucherrechte",
"quote": "Die Schülerinnen und Schüler können … ökonomische Phänomene und Zusammenhänge (Einkommens- bzw. Vermögensunterschiede, Wohlstand, Verteilungsgerechtigkeit, alternative Konsumformen, Sozialversicherung) beschreiben und analysieren; ihre Rechte und Pflichten als Verbraucherinnen und Verbraucher in konkreten Lebenssituationen beschreiben und nutzen … die Aufgabe von Wirtschaft und Staat sowie den Sinn … in Zusammenhang mit dem Wirtschaftskreislauf beschreiben …",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0005_602132D5_6AB7_4D68_B4E4_6CF508085BA2.pdfsig",
"reference_seite": "16 von 151",
"passende_sims": ["weltkueche", "logistik", "busfahrt", "farmer"],
"passende_plattform_kompetenzen": ["wirtschaft-logistikverstaendnis", "neu:ernaehrungs-und-konsumkompetenz"],
"neu_oder_vorhanden": "vorhanden"
},
{
"code": "VS Sachunterricht — Geografischer Kompetenzbereich 4. Schulstufe",
"subject": "Sachunterricht",
"school_type": "VS",
"grade": "4. Schulstufe (910 J.)",
"title": "Raumnutzung, Veränderungen in Räumen, Mensch-Raum-Abhängigkeit",
"quote": "Die Schülerinnen und Schüler können die unterschiedliche Nutzung von Räumen durch Menschen erschließen, vergleichen und einschätzen; Veränderungen in Räumen erkennen, über deren Folgen diskutieren und Ideen für die künftige Entwicklung und Gestaltung präsentieren. Zusammenhänge und Abhängigkeiten zwischen Lebensweisen und Lebensräumen von Menschen wahrnehmen, einschätzen und persönliche Schlussfolgerungen ableiten.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0001_CE7F0AA2_A925_4A4D_8C3C_355D12BD22D1.pdfsig",
"reference_seite": "83 von 130 (VS Anlage 1)",
"passende_sims": ["fluss", "klima", "klima-3d", "farmer", "busfahrt"],
"passende_plattform_kompetenzen": ["stadtplanung-raum", "naturgefahren-hochwasser", "landwirtschaft-klimazonen"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "Volksschule 4. Klasse — Raumnutzung erstmals abgedeckt"
},
{
"code": "VS Sachunterricht — Geografischer Kompetenzbereich 3. Schulstufe",
"subject": "Sachunterricht",
"school_type": "VS",
"grade": "3. Schulstufe (89 J.)",
"title": "Mobilität von Menschen, Gütern, Nachrichten; globale Folgen",
"quote": "Die Schülerinnen und Schüler können Elemente und Merkmale von Räumen in Darstellungsmitteln auffinden, raumbezogene Orientierungsraster aufbauen und interpretieren sowie analoge und digitale Orientierungsmittel anwenden. Formen der Mobilität von Menschen, Gütern und Nachrichten erkunden sowie Nutzen und globale Folgen für die Menschen und die Umwelt abschätzen.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0001_CE7F0AA2_A925_4A4D_8C3C_355D12BD22D1.pdfsig",
"reference_seite": "82 von 130",
"passende_sims": ["busfahrt", "logistik", "heli", "weltkueche"],
"passende_plattform_kompetenzen": ["raeumliche-orientierung-europa", "kartenkompetenz-logistik", "wirtschaft-logistikverstaendnis"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "VS 3. Schulstufe — Mobilität von Gütern (globale Folgen) — passt zu Welthandel/Lieferketten"
},
{
"code": "VS Sachunterricht — Wirtschaftlicher Kompetenzbereich 4. Schulstufe",
"subject": "Sachunterricht",
"school_type": "VS",
"grade": "4. Schulstufe (910 J.)",
"title": "Wirtschaftskreislauf ProduktionHandelKonsum, Konsumentscheidungen, Nachhaltigkeit",
"quote": "Die Schülerinnen und Schüler können wirtschaftliche Regeln und Zusammenhänge sowie den wirtschaftlichen Kreislauf von Produktion, Handel und Konsum erkennen und dokumentieren; Gründe und Kriterien für Konsumentscheidungen bewerten; wirtschaftliche, gesundheitliche und soziale Folgen von Konsum diskutieren. Die Bedeutung eines bewussten Handelns für Umweltschutz und Nachhaltigkeit erklären und das eigene Konsumverhalten reflektieren.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0001_CE7F0AA2_A925_4A4D_8C3C_355D12BD22D1.pdfsig",
"reference_seite": "83 von 130",
"passende_sims": ["weltkueche", "logistik", "farmer", "busfahrt"],
"passende_plattform_kompetenzen": ["wirtschaft-logistikverstaendnis", "neu:ernaehrungs-und-konsumkompetenz"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "VS 4. Schulstufe — Welthandel/Konsum-Kreislauf für 910-J. abgedeckt"
},
{
"code": "VS Sachunterricht — Wirtschaftlicher Kompetenzbereich 3. Schulstufe",
"subject": "Sachunterricht",
"school_type": "VS",
"grade": "3. Schulstufe (89 J.)",
"title": "Produktion, Weg der Güter, Angebot/Nachfrage, Knappheit",
"quote": "Die Schülerinnen und Schüler können die Produktion und den Weg von Gütern erkunden und beschreiben, Rahmenbedingungen von Produktion und Konsum wahrnehmen sowie über die Verwendung von Gütern nachdenken. Das Prinzip des Kaufvorgangs in realen wie virtuellen Marktplätzen beschreiben und über die Bedeutung der verfügbaren Mittel (Angebot und Nachfrage, Knappheit) für Kaufentscheidungen reflektieren.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0001_CE7F0AA2_A925_4A4D_8C3C_355D12BD22D1.pdfsig",
"reference_seite": "82 von 130",
"passende_sims": ["weltkueche", "logistik", "farmer", "busfahrt"],
"passende_plattform_kompetenzen": ["wirtschaft-logistikverstaendnis", "planungs-entscheidungskompetenz"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "VS 3. Schulstufe — Welthandel/Güterketten/Märkte für 89-J."
},
{
"code": "VS Sachunterricht — Naturwissenschaftlicher Kompetenzbereich 4. Schulstufe",
"subject": "Sachunterricht",
"school_type": "VS",
"grade": "4. Schulstufe (910 J.)",
"title": "Energie und Energieumwandlungen im Alltag",
"quote": "Die Schülerinnen und Schüler können Entwicklungsstadien und Lebenszyklen bei Menschen, Tieren und Pflanzen beobachten, bestimmen und Artenvielfalt kategorisieren; die Entwicklung menschlichen Lebens von der Zeugung bis zur Geburt beschreiben. Die Bedeutung von Energie und Energieumwandlungen im Alltag erkennen, beschreiben und reflektiert handeln.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0001_CE7F0AA2_A925_4A4D_8C3C_355D12BD22D1.pdfsig",
"reference_seite": "83 von 130",
"passende_sims": ["energiemanager", "klima", "klima-3d"],
"passende_plattform_kompetenzen": ["energieversorgung-speicherung", "klimawandel"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "VS 4. Schulstufe — Energieumwandlung"
},
{
"code": "VS Sachunterricht — Anwendungsbereiche 4. Schulstufe",
"subject": "Sachunterricht",
"school_type": "VS",
"grade": "4. Schulstufe (910 J.)",
"title": "Anwendungsbereiche 4. Schulstufe (Liste)",
"quote": "Anwendungsbereiche: Fortpflanzung und Körperwahrnehmung; Politik und Global Citizenship; Vergangenheit Gegenwart Zukunft; Nachhaltigkeit und Verantwortung; Nah und fern; Energie und Materie; Bionik und Robotik; Information und Social Media; Versorgung und Entsorgung; Entwicklung und Veränderung.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0001_CE7F0AA2_A925_4A4D_8C3C_355D12BD22D1.pdfsig",
"reference_seite": "83 von 130",
"passende_sims": ["eu-werkstatt", "weltkueche", "klima", "klima-3d", "energiemanager"],
"passende_plattform_kompetenzen": ["eu-politische-beteiligung", "klimawandel", "energieversorgung-speicherung"],
"neu_oder_vorhanden": "vorhanden",
"luecke_geschlossen": "VS 4. Schulstufe — Global Citizenship, Nachhaltigkeit als verbindliche Anwendungsbereiche"
},
{
"code": "VS Sachunterricht — Anwendungsbereiche 3. Schulstufe",
"subject": "Sachunterricht",
"school_type": "VS",
"grade": "3. Schulstufe (89 J.)",
"title": "Anwendungsbereiche 3. Schulstufe (Liste)",
"quote": "Anwendungsbereiche: Entwicklungsstadien und Lebenszyklen; Kinderrechte und Diversität; Geografische Gegebenheiten und Orientierung; Geschichte und Ereignisse; Öffentliche Einrichtungen und Institutionen; Erfindungen und Entdeckungen; Produktion und Handel; Klima und Wetter; Stoffe und Veränderungen; Kräfte und Wirkungen.",
"reference_url": "https://www.ris.bka.gv.at/Dokumente/BgblAuth/BGBLA_2023_II_1/Anlagen_0001_CE7F0AA2_A925_4A4D_8C3C_355D12BD22D1.pdfsig",
"reference_seite": "82 von 130",
"passende_sims": ["weltkueche", "klima", "klima-3d", "busfahrt", "logistik"],
"passende_plattform_kompetenzen": ["wirtschaft-logistikverstaendnis", "klimawandel"],
"neu_oder_vorhanden": "vorhanden"
}
],
"neu_vorgeschlagene_plattform_kompetenzen": [
{
"key_slug": "ernaehrungs-und-konsumkompetenz",
"title": "Ernährungs- und Konsumkompetenz",
"category": "gesellschaft",
"age_min": 10,
"age_max": 16,
"description": "Lebensmittel-Auswahl unter Aspekten von Gesundheit, Saisonalität, Regionalität, Nachhaltigkeit und globaler Produktion. Verantwortlicher Konsum, Produktlinienanalyse, Vermeidung von Lebensmittelverschwendung. Begründet im EH-Lehrplan (2. Kl. MS) sowie im übergreifenden Thema 13.",
"primaer_fuer_sims": ["weltkueche"],
"sekundaer_fuer_sims": ["farmer", "logistik"],
"begruendung_aus_lehrplan": "EH 2. Klasse Kompetenzbereich 'Ernährung, Gesundheit und Soziales' + 'Lebensgestaltung, Wirtschaft und Produktion'; Übergreifendes Thema 13 Wirtschafts-/Finanz-/Verbraucher:innenbildung."
}
],
"luecken_themen": [
{
"thema": "Plantage / Monokultur (als Begriff)",
"befund": "Die Lehrpläne sprechen von 'konventioneller vs. biologischer Landwirtschaft' (BU 4. Kl.) und 'anthropogenen Einflüssen' — aber die Begriffe 'Plantage' und 'Monokultur' kommen wörtlich NICHT vor. Über BU 4. Kl. Anwendungsbereich (Charakteristika der konventionellen Landwirtschaft) sinngemäß abgedeckt. Konsequenz: kein wörtliches Zitat möglich — als 'sinngemäß abgedeckt durch BU 4. Kl.' dokumentieren, nicht als eigenständiger Anker."
},
{
"thema": "Fair Trade / fairer Handel (Begriff)",
"befund": "Begriff kommt im GW- und EH-Lehrplan wörtlich NICHT vor. Sinngemäß abgedeckt durch GW 4.3 'Möglichkeiten und Grenzen … nachhaltige[r] wirtschaftliche[r] Aktivitäten und Beziehungen in der globalisierten Welt' und Übergreifendes Thema 11 ('sozial gerechte Ressourcen- und Energienutzung'). Kein wörtliches Zitat — daher kein eigenständiger Anker hinzugefügt."
},
{
"thema": "Klimazonen explizit (Köppen-Geiger)",
"befund": "Begriff 'Klimazonen' kommt im GW-Sek-I-Lehrplan wörtlich NICHT vor. Indirekt abgedeckt durch GW 1.3 (naturräumliche Bedingungen weltweiter landwirtschaftlicher Fallbeispiele) + GW 4.1 (Belastungsgrenzen) + VS Sachunterricht 'Klima und Wetter' (3. Schulstufe). Die Plattform-Kompetenz 'landwirtschaft-klimazonen' (Farmer) bezieht ihre Lehrplan-Verankerung daher indirekt; einen wörtlichen Anker gibt es nur über VS 3. Schulstufe (Anwendungsbereich 'Klima und Wetter'). Bestätigt: KEIN expliziter Sek-I-Lehrplan-Anker zu Köppen-Geiger."
},
{
"thema": "EU-Institutionen (Kommission, Parlament, Ministerrat, Europäischer Rat) namentlich",
"befund": "Die genannten Organe werden im GW-Lehrplan NICHT namentlich aufgezählt; GW 4.2 spricht nur abstrakt von 'EU-Institutionen' (sinngemäß), wörtlich werden 'vier Grundfreiheiten, Euro, Bildungskooperationen, Qualitätsstandards, Verbraucherschutz, Regionalentwicklung' genannt. Die EU-Werkstatt-Inhalte (Kommission/Parlament/Ministerrat/Rat) sind über GW 4.2 + GPB 4. Klasse ('EU als Wirtschafts- und Friedensprojekt') verankert, ohne wörtliche Institutionennamen."
},
{
"thema": "Volksschule 1.2. Schulstufe",
"befund": "Bewusst weggelassen — Zielalter GeoGraSim ist 1014 J., daher nur VS 3.+4. Schulstufe (810 J.) relevant. VS-Anker oben decken die Untergrenze ab."
},
{
"thema": "Mathematik / Physik / Chemie / Bewegung und Sport für Sek I",
"befund": "Bestehende DB hat 10 Mathe + 7 Physik + 2 Chemie + 2 BSP AT-Anker. Diese Recherche fokussierte vereinbarungsgemäß die GW/EH/BU/GPB/Übergreifenden-Themen-Lücken (Welthandel, Welternährung, EU, Klimazonen, VS). Mathematik/Physik wurden nicht erneut durchgekämmt — bei Bedarf separate Runde."
}
]
}
File diff suppressed because it is too large Load Diff
@@ -1,607 +0,0 @@
{
"meta": {
"title": "GeoGraSim DE-Lehrplan-Recherche Sek I (Klasse 5-10)",
"erstellt": "2026-06-08",
"instanz": "Atlas",
"scope": "Bayern (Gymnasium + Realschule LehrplanPLUS), NRW (Kernlehrplan Gymnasium G9 ab 2019), Niedersachsen (Kerncurriculum Gymnasium 5-10), KMK/DGfG Bildungsstandards Mittlerer Schulabschluss 2020 (10. Auflage)",
"quellen_geladen": [
"https://vgdh.de/wp-content/uploads/2023/08/Bildungsstandards_Geographie_2020_Web.pdf (PDF -> pdftotext, 4894 Zeilen)",
"https://lehrplannavigator.nrw.de/system/files/media/document/file/g9_ek_klp_3408_2019_06_23.pdf (PDF -> pdftotext, 1270 Zeilen)",
"https://cuvo.nibis.de/cuvo.php?p=download&upload=61 (Webfetch 403, ueber caeci.de/files/seiten/erdkunde/kc%20Sek%201%20Ek.pdf -> pdftotext, 1054 Zeilen)",
"https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/5/geographie (HTML)",
"https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/7/geographie (HTML)",
"https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/10/geographie (HTML)",
"https://www.lehrplanplus.bayern.de/fachlehrplan/lernbereich/66557 (HTML, Klima und Klimawandel)",
"https://www.lehrplanplus.bayern.de/fachlehrplan/lernbereich/66374 (HTML, Planetarische Grundlagen)",
"https://www.lehrplanplus.bayern.de/fachlehrplan/realschule/8/geographie (HTML)",
"https://www.lehrplanplus.bayern.de/fachlehrplan/realschule/9/geographie (HTML)"
],
"quellen_nicht_geladen": [
"https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/8/geographie (WebFetch lieferte nur Homepage-Navigation, KEIN Inhalt extrahierbar)",
"https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/9/geographie (idem)",
"https://www.lehrplanplus.bayern.de/jahrgangsstufenprofil/gymnasium/8/geographie (idem)"
],
"kompetenz_id_legende": {
"1": "klimawandel",
"2": "naturgefahren-hochwasser",
"3": "karten-navigation-alpen",
"4": "stadtplanung-raum",
"5": "raeumliche-orientierung-europa",
"6": "kartenkompetenz-logistik",
"7": "wirtschaft-logistikverstaendnis",
"8": "planungs-entscheidungskompetenz",
"9": "verkehrserziehung-sicherheit",
"10": "systemisches-denken",
"11": "energieversorgung-speicherung",
"12": "erdmechanik-klimazonen",
"13": "eu-politische-beteiligung",
"14": "landwirtschaft-klimazonen"
},
"sim_slugs_aktiv": [
"klima", "klima-3d", "fluss", "heli", "energiemanager", "eu-werkstatt",
"farmer", "busfahrt", "sonnensystem", "logistik", "weltkueche"
],
"regeln": [
"Wörtliche Zitate, max 500 Zeichen.",
"Pro Eintrag genau eine Quelle (PDF oder Lehrplan-Seite).",
"Bei Unsicherheit weglassen.",
"Sim-Empfehlung ist Vorschlag, keine endgueltige Zuordnung — Thomas entscheidet.",
"Kompetenz-Empfehlung verweist auf bestehende 14 GeoGraSim-Plattform-Kompetenzen ODER markiert 'neu_nötig'."
]
},
"kmk_dgfg_bildungsstandards_2020": {
"quelle": "Deutsche Gesellschaft für Geographie e.V. (Hrsg.): Bildungsstandards im Fach Geographie für den Mittleren Schulabschluss mit Aufgabenbeispielen. 10., aktualisierte und überarbeitete Auflage Juli 2020. Bonn 2020.",
"url": "https://vgdh.de/wp-content/uploads/2023/08/Bildungsstandards_Geographie_2020_Web.pdf",
"hinweis": "Diese Standards wurden NICHT von der KMK, sondern von der DGfG entwickelt und gelten als de-facto-nationaler Standard, auf den die meisten Bundeslaender ihre Lehrplaene beziehen.",
"anker": [
{
"code": "DGfG-F1",
"kompetenzbereich": "Fachwissen",
"titel": "F1 Fähigkeit, die Erde als Planeten zu beschreiben",
"quote": "S11 grundlegende planetare Merkmale (z.B. Größe, Gestalt, Aufbau, Neigung der Erdachse, Gravitation) beschreiben, S2 die Stellung und die Bewegungen der Erde im Sonnensystem und deren Auswirkungen erläutern (Tag und Nacht, Jahreszeiten).",
"seite": "S. 12-13",
"sim_vorschlag": ["sonnensystem"],
"kompetenz_vorschlag": 12,
"begruendung": "Direkter Match zu erdmechanik-klimazonen — Erdrevolution, Achsneigung, Tag/Nacht/Jahreszeiten."
},
{
"code": "DGfG-F2",
"kompetenzbereich": "Fachwissen",
"titel": "F2 Fähigkeit, Räume unterschiedlicher Art und Größe als naturgeographische Systeme zu erfassen",
"quote": "S4 gegenwärtige naturgeographische Phänomene und Strukturen in Räumen (z.B. Vulkane, Erdbeben, Gewässernetz, Karstformen) beschreiben und erklären; S7 den Ablauf von naturgeographischen Prozessen in Räumen (z.B. Verwitterung, Wettergeschehen, Gebirgsbildung) darstellen; S8 das Zusammenwirken von Geofaktoren und einfache Kreisläufe (z.B. Höhenstufen der Vegetation, Meeresströmungen und Klima, Ökosystem tropischer Regenwald, Wasserkreislauf) als System darstellen.",
"seite": "S. 13-14",
"sim_vorschlag": ["fluss", "klima", "klima-3d", "sonnensystem"],
"kompetenz_vorschlag": 2,
"begruendung": "Naturgeographische Prozesse — Wasserkreislauf (fluss), Klimasystem (klima), Höhenstufen (heli)."
},
{
"code": "DGfG-F3",
"kompetenzbereich": "Fachwissen",
"titel": "F3 Fähigkeit, Räume unterschiedlicher Art und Größe als humangeographische Systeme zu erfassen",
"quote": "S12 den Ablauf von humangeographischen Prozessen in Räumen (z.B. Strukturwandel, Verstädterung, wirtschaftliche Globalisierung) beschreiben und erklären; S13 das Zusammenwirken von Faktoren in humangeographischen Systemen (z.B. Bevölkerungspolitik, Welthandel, Megastädte) erläutern.",
"seite": "S. 14",
"sim_vorschlag": ["logistik", "busfahrt", "eu-werkstatt", "weltkueche"],
"kompetenz_vorschlag": 7,
"begruendung": "Welthandel und globale Lieferketten als humangeographisches System — Kernthema Logistik/Busfahrt/Weltküche."
},
{
"code": "DGfG-F4",
"kompetenzbereich": "Fachwissen",
"titel": "F4 Fähigkeit, Mensch-Umwelt-Beziehungen in Räumen unterschiedlicher Art und Größe zu analysieren",
"quote": "S18 Auswirkungen der Nutzung und Gestaltung von Räumen (z.B. Rodung, Gewässerbelastung, Bodenerosion, Naturrisiken, Klimawandel, Wassermangel, Bodenversalzung) erläutern; S20 mögliche ökologisch, sozial und/oder ökonomisch sinnvolle Maßnahmen zur Entwicklung und zum Schutz von Räumen (z.B. Tourismusförderung, Aufforstung, Biotopvernetzung, Geotopschutz) erläutern.",
"seite": "S. 14-15",
"sim_vorschlag": ["klima", "klima-3d", "farmer", "fluss"],
"kompetenz_vorschlag": 1,
"begruendung": "Klimawandel als Mensch-Umwelt-Wechselwirkung explizit erwaehnt — klima/klima-3d primaer."
},
{
"code": "DGfG-O1",
"kompetenzbereich": "Räumliche Orientierung",
"titel": "O1 Kenntnis grundlegender topographischer Wissensbestände",
"quote": "S1 verfügen auf den unterschiedlichen Maßstabsebenen über ein basales Orientierungswissen (z.B. Name und Lage der Kontinente und Ozeane, der großen Gebirgszüge der Erde, der einzelnen Bundesländer, von großen europäischen Städten und Flüssen); S2 kennen grundlegende räumliche Orientierungsraster und Ordnungssysteme (z.B. das Gradnetz, die Klima- und Landschaftszonen der Erde).",
"seite": "S. 16-17",
"sim_vorschlag": ["busfahrt", "logistik", "fluggesellschaft"],
"kompetenz_vorschlag": 5,
"begruendung": "Topographisches Europa-Wissen — Kernziel der Busfahrt-/Logistik-Sim."
},
{
"code": "DGfG-O3",
"kompetenzbereich": "Räumliche Orientierung",
"titel": "O3 Fähigkeit zu einem angemessenen Umgang mit Karten (Kartenkompetenz)",
"quote": "S6 topographische, physische, thematische und andere alltagsübliche Karten im Web oder anderen Quellen finden, lesen und unter einer zielführenden Fragestellung auswerten; S8 topographische Übersichtsskizzen und einfache Karten analog und digital anfertigen.",
"seite": "S. 17-18",
"sim_vorschlag": ["heli", "logistik", "busfahrt"],
"kompetenz_vorschlag": 6,
"begruendung": "Direkter Match zu kartenkompetenz-logistik."
},
{
"code": "DGfG-O4",
"kompetenzbereich": "Räumliche Orientierung",
"titel": "O4 Fähigkeit zur Orientierung in Realräumen",
"quote": "S11 mit Hilfe einer Karte und anderer Orientierungshilfen (z.B. Landmarken, Straßennamen, Himmelsrichtungen, mobilen Geräten zur Standortermittlung) ihren Standort im Realraum bestimmen; S13 sich mit Hilfe von Karten und anderen Orientierungshilfen (z.B. Landmarken, Piktogrammen, Kompass, Diensten zur Routenplanung, Augmented Reality) im Realraum bewegen; S14 schematische Darstellungen von Verkehrsnetzen anwenden.",
"seite": "S. 18",
"sim_vorschlag": ["heli", "busfahrt"],
"kompetenz_vorschlag": 3,
"begruendung": "Routenplanung mit Kompass und Karte — Kern der Heli-Sim. Verkehrsnetze fuer Busfahrt."
},
{
"code": "DGfG-M2",
"kompetenzbereich": "Erkenntnisgewinnung/Methoden",
"titel": "M2 Fähigkeit, Informationen zur Behandlung von geographischen Fragestellungen zu gewinnen",
"quote": "S4 problem-, sach- und zielgemäß Informationen aus geographisch relevanten Informationsformen/-medien auswählen; S5 problem-, sach- und zielgemäß Informationen im Gelände (z.B. Beobachten, Kartieren, Messen, Zählen, Probennahme, Befragen) oder durch einfache Versuche und klassische Experimente gewinnen.",
"seite": "S. 19-20",
"sim_vorschlag": ["klima", "klima-3d", "farmer"],
"kompetenz_vorschlag": null,
"begruendung": "Querschnittskompetenz — keiner einzelnen GGS-Kompetenz zuzuordnen, gilt in allen Sims."
},
{
"code": "DGfG-B1",
"kompetenzbereich": "Beurteilung/Bewertung",
"titel": "B1 Fähigkeit, ausgewählte Situationen/Sachverhalte im Raum unter Anwendung geographischer Kenntnisse zu beurteilen",
"quote": "S2 geographische Kenntnisse und die o.g. Kriterien anwenden, um ausgewählte geographisch relevante Sachverhalte, Ereignisse, Herausforderungen und Risiken (z.B. Migration, Hochwasser, Entwicklungshilfe, Flächennutzungskonflikte, Konflikte beim Zusammentreffen von Kulturen, Bürgerkriege, Ressourcenkonflikte) zu beurteilen.",
"seite": "S. 23-24",
"sim_vorschlag": ["fluss", "klima", "eu-werkstatt", "weltkueche"],
"kompetenz_vorschlag": 2,
"begruendung": "Hochwasser ausdruecklich genannt — naturgefahren-hochwasser."
},
{
"code": "DGfG-B4",
"kompetenzbereich": "Beurteilung/Bewertung",
"titel": "B4 Fähigkeit, ausgewählte Sachverhalte/Prozesse unter Einbeziehung fachbasierter und fachübergreifender Werte und Normen zu bewerten",
"quote": "S7 geographisch relevante Werte und Normen (z.B. Menschenrechte, Naturschutz, Nachhaltigkeit) nennen; S8 geographisch relevante Sachverhalte und Prozesse (z.B. Flussregulierung, Tourismus, globale Ordnungen, Entwicklungshilfe/wirtschaftliche Zusammenarbeit, Ressourcennutzung) in Hinblick auf diese Normen und Werte bewerten.",
"seite": "S. 24-25",
"sim_vorschlag": ["eu-werkstatt", "weltkueche", "farmer", "klima"],
"kompetenz_vorschlag": 13,
"begruendung": "Globale Ordnungen, Werte/Normen — EU-Werkstatt-Kern. Auch Welternaehrung."
},
{
"code": "DGfG-H3",
"kompetenzbereich": "Handlung",
"titel": "H3 Bereitschaft zum konkreten Handeln in geographisch relevanten Situationen",
"quote": "S8 fachlich fundiert raumpolitische Entscheidungsprozesse nachzuvollziehen und daran zu partizipieren (z.B. Planungsvorschläge an den Gemeinderat, Beteiligung an der Lokalen Agenda des Heimatortes); S9 sich in ihrem Alltag für eine bessere Qualität der Umwelt, eine nachhaltige Entwicklung, für eine interkulturelle Verständigung und eine Begegnung auf Augenhöhe mit Menschen anderer Regionen sowie ein friedliches und gerechtes Zusammenleben in der Einen Welt einzusetzen.",
"seite": "S. 27",
"sim_vorschlag": ["eu-werkstatt", "klima", "weltkueche"],
"kompetenz_vorschlag": 13,
"begruendung": "Raumpolitische Beteiligung — Kern der EU-Werkstatt-Buergerinitiative."
}
]
},
"nrw_kernlehrplan_erdkunde_gymnasium_g9": {
"quelle": "Ministerium für Schule und Bildung des Landes Nordrhein-Westfalen: Kernlehrplan für die Sekundarstufe I Gymnasium in Nordrhein-Westfalen — Erdkunde. Heft 3408. Düsseldorf 2019 (aufsteigend ab 2019/20).",
"url": "https://lehrplannavigator.nrw.de/system/files/media/document/file/g9_ek_klp_3408_2019_06_23.pdf",
"schulform": "Gymnasium (G9)",
"klassen": "5-10",
"anker": [
{
"code": "NRW-IF1",
"titel": "Inhaltsfeld 1: Unterschiedlich strukturierte Siedlungen",
"quote": "Das Inhaltsfeld umfasst die Funktion, Struktur und Veränderung ländlicher bzw. suburbaner und städtischer Siedlungen sowie die funktionale und verkehrliche Beziehung zwischen diesen. Inhaltliche Schwerpunkte: physiognomische Merkmale von Siedlungen; Daseinsgrundfunktionen in Siedlungen: Wohnen, Arbeit, Versorgung, Erholung, Bildung und Mobilität; Stadt-Umlandbeziehungen; funktionsräumliche Gliederung städtischer Teilräume.",
"seite": "S. 14, 18-19",
"klassenstufe": "Jg. 5-6 (Erprobungsstufe)",
"sim_vorschlag": ["busfahrt"],
"kompetenz_vorschlag": 4,
"begruendung": "Stadt-Umland, Daseinsgrundfunktionen — stadtplanung-raum. Busfahrt-Sim deckt Pendler-/Verkehrsachsen."
},
{
"code": "NRW-IF2",
"titel": "Inhaltsfeld 2: Räumliche Voraussetzungen und Auswirkungen des Tourismus",
"quote": "In diesem Inhaltsfeld wird die naturräumliche Ausstattung in ihrer Bedeutung für eine wirtschaftliche Nutzung durch den Tourismus behandelt. Inhaltliche Schwerpunkte: Formen des Tourismus: Erholungs-, Öko- und Städtetourismus; touristisches Potenzial: Temperatur und Niederschlag, Küsten- und Gebirgslandschaft, touristische Infrastruktur; Merkmale des sanften Tourismus. Topographisches Orientierungsraster: Tourismus- und Erholungsregionen in Deutschland und Europa.",
"seite": "S. 14, 20",
"klassenstufe": "Jg. 5-6",
"sim_vorschlag": ["heli", "busfahrt"],
"kompetenz_vorschlag": 3,
"begruendung": "Gebirgslandschaft + touristische Infrastruktur — Heli-Bergrettung in Alpen-Tourismusregion."
},
{
"code": "NRW-IF3",
"titel": "Inhaltsfeld 3: Arbeit und Versorgung in Wirtschaftsräumen unterschiedlicher Ausstattung",
"quote": "Inhaltliche Schwerpunkte: Standortfaktoren des primären Sektors: Boden, Klima; Produktionskette von Nahrungsmitteln: Herstellung, Verarbeitung, Transport, Handel; strukturelle Veränderungsprozesse in der Landwirtschaft: Intensivierung, Spezialisierung; nachhaltiges Wirtschaften in der Landwirtschaft; Standortfaktoren des sekundären Sektors: Rohstoffe, Arbeitskräfte, Verkehrsinfrastruktur.",
"seite": "S. 14, 21-22",
"klassenstufe": "Jg. 5-6",
"sim_vorschlag": ["farmer", "weltkueche", "logistik", "busfahrt"],
"kompetenz_vorschlag": 14,
"begruendung": "Standortfaktoren primaer (Boden, Klima) — farmer. Produktionskette Nahrungsmittel — weltkueche."
},
{
"code": "NRW-IF4",
"titel": "Inhaltsfeld 4: Aufbau und Dynamik der Erde",
"quote": "Lebens- und Wirtschaftsräume im Bereich der Schwächezonen der Erde sind in besonderer Weise Naturrisiken ausgesetzt. Inhaltliche Schwerpunkte: Schalenbau der Erde: Erdkern, -mantel, -kruste; Plattentektonik: Konvergenz, Divergenz, Subduktion; Naturereignisse: Erd- und Seebeben, Vulkanismus; Leben und Wirtschaften in Risikoräumen: Landwirtschaft, Rohstoffe, Tourismus, Energie.",
"seite": "S. 14, 25-26",
"klassenstufe": "Jg. 7-10 (Sek I)",
"sim_vorschlag": ["sonnensystem"],
"kompetenz_vorschlag": 12,
"begruendung": "Plattentektonik/Vulkanismus eng verwandt mit erdmechanik-klimazonen — Sonnensystem deckt Erdaufbau peripher."
},
{
"code": "NRW-IF5",
"titel": "Inhaltsfeld 5: Wetter und Klima",
"quote": "Inhaltliche Schwerpunkte: Himmelskörper Erde: Schrägstellung der Erdachse, Beleuchtungszonen, Temperaturzonen, Jahreszeiten; Klima und Klimasystem: Aufbau der Atmosphäre, Klimaelemente, Wasserkreislauf, Luftbewegungen, planetarische Zirkulation; Ursachen und Auswirkungen globaler Klimaschwankungen: Treibhauseffekt, Meeresspiegelanstieg, Wetterextreme. Topographisches Orientierungsraster: Klimazonen der Erde.",
"seite": "S. 14, 26-27",
"klassenstufe": "Jg. 7-10",
"sim_vorschlag": ["klima", "klima-3d", "sonnensystem"],
"kompetenz_vorschlag": 1,
"begruendung": "Treibhauseffekt + Meeresspiegelanstieg + Wetterextreme = klima/klima-3d-Kern. Beleuchtungszonen = sonnensystem."
},
{
"code": "NRW-IF6",
"titel": "Inhaltsfeld 6: Landwirtschaftliche Produktion in unterschiedlichen Landschaftszonen",
"quote": "Inhaltliche Schwerpunkte: naturräumliche Bedingungen in den Tropen, Subtropen und Mittelbreiten; Wirtschaftsformen und ökonomische Rahmenbedingungen: Ackerbau, Viehwirtschaft, Plantagenwirtschaft, Subsistenzwirtschaft, marktorientierte Produktion; Möglichkeiten der Überwindung natürlicher Grenzen: Agroforstwirtschaft, Bewässerung, Treibhauskulturen; Folgen unangepasster Nutzung: Regenwaldzerstörung, Desertifikation, Bodenversalzung, Erosion.",
"seite": "S. 14, 27-28",
"klassenstufe": "Jg. 7-10",
"sim_vorschlag": ["farmer", "weltkueche"],
"kompetenz_vorschlag": 14,
"begruendung": "Direkter Match zu landwirtschaft-klimazonen. Farmer-Sim deckt Tropen/Subtropen/Mittelbreiten und Bewaesserung."
},
{
"code": "NRW-IF7",
"titel": "Inhaltsfeld 7: Innerstaatliche und globale Disparitäten",
"quote": "Inhaltliche Schwerpunkte: Entwicklungsindikatoren in den Bereichen Bildung, Demographie, Ernährung, Gesundheit, Infrastruktur, Wirtschaft, Human Development Index (HDI), Gender Development Index (GDI); Länder und Regionen unterschiedlichen Entwicklungsstandes; Möglichkeiten zur Entwicklung strukturschwacher und wenig entwickelter Räume; Projekte der Entwicklungszusammenarbeit, Handelsabkommen.",
"seite": "S. 14-15, 28-29",
"klassenstufe": "Jg. 7-10",
"sim_vorschlag": ["weltkueche", "farmer"],
"kompetenz_vorschlag": null,
"begruendung": "Entwicklungsdisparitaeten + Welternaehrung — kein 1:1 Match in den 14 Plattform-Kompetenzen. Vorschlag: neue Plattform-Kompetenz 'welternaehrung-disparitaeten' oder welternaehrung als Subkategorie unter landwirtschaft-klimazonen."
},
{
"code": "NRW-IF9",
"titel": "Inhaltsfeld 9: Verstädterung und Stadtentwicklung",
"quote": "Inhaltliche Schwerpunkte: grundlegende genetische, funktionale und soziale Merkmale, innere Differenzierung und Wandel von Städten; Phänomene der Verstädterung: Urbanisierung, Herausbildung von Megacities, Metropolisierung, Segregation; Schwerpunkte aktueller Stadtentwicklung: Mobilität, Umweltbelastung, demographischer und sozialer Wandel, Wohnraumverfügbarkeit. Topographisches Orientierungsraster: Agglomerationsräume Europas und der Erde.",
"seite": "S. 15, 31",
"klassenstufe": "Jg. 7-10",
"sim_vorschlag": ["busfahrt"],
"kompetenz_vorschlag": 4,
"begruendung": "Mobilitaet, Urbanisierung, Agglomerationsraeume Europas — Busfahrt deckt EU-Metropolen, stadtplanung-raum als Sekundaer-Kompetenz."
},
{
"code": "NRW-IF10",
"titel": "Inhaltsfeld 10: Räumliche Strukturen unter dem Einfluss von Globalisierung und Digitalisierung",
"quote": "Inhaltliche Schwerpunkte: Merkmale von Globalisierung in Gesellschaft, Ökologie, Ökonomie und Politik; Raumwirksamkeit von Globalisierung: veränderte Standortgefüge, multinationale Konzerne, Global Cities; Wandel von Unternehmen im Zuge der Digitalisierung: Just-in-time-Produktion, Outsourcing; Raumwirksamkeit von Digitalisierung: Standortfaktor digitale Infrastruktur, Onlinehandel, Verlagerung von Arbeitsplätzen, digital vernetzte Güter- und Personenverkehre.",
"seite": "S. 15-16, 31-32",
"klassenstufe": "Jg. 7-10",
"sim_vorschlag": ["logistik", "busfahrt", "eu-werkstatt", "weltkueche"],
"kompetenz_vorschlag": 7,
"begruendung": "Just-in-time + Gueterverkehre = wirtschaft-logistikverstaendnis und systemisches-denken — Logistik-Kern."
},
{
"code": "NRW-SK-Sek1",
"titel": "Übergeordnete Sachkompetenz Sek I (bis Ende Jg. 10)",
"quote": "SK1 beschreiben einzelne Geofaktoren und deren Zusammenwirken sowie ihren Einfluss auf den menschlichen Lebensraum; SK2 verdeutlichen Wirkungen und Folgen von Eingriffen des Menschen in das Geofaktorengefüge; SK3 analysieren durch wirtschaftliche, soziale und politische Faktoren beeinflusste räumliche Strukturen und Entwicklungsprozesse; SK4 erläutern Raumnutzungsansprüche und -konflikte.",
"seite": "S. 22-23",
"klassenstufe": "Jg. 7-10",
"sim_vorschlag": ["klima", "klima-3d", "fluss", "farmer"],
"kompetenz_vorschlag": 10,
"begruendung": "Geofaktoren-Zusammenwirken = systemisches-denken; gilt als Querschnitt fuer mehrere Sims."
},
{
"code": "NRW-MK12-Sek1",
"titel": "MK12 — GIS-Analysen",
"quote": "MK12 führen einfache Analysen mithilfe interaktiver Kartendienste und Geographischer Informationssysteme (GIS) durch.",
"seite": "S. 23",
"klassenstufe": "Jg. 7-10",
"sim_vorschlag": ["heli", "logistik", "busfahrt"],
"kompetenz_vorschlag": 6,
"begruendung": "Interaktive Kartendienste — Kartenkompetenz-logistik; Heli nutzt 2D/3D-Karten interaktiv."
},
{
"code": "NRW-HK1",
"titel": "Übergeordnete Handlungskompetenz Erprobungsstufe (Jg. 5/6)",
"quote": "HK1 vertreten probehandelnd in Raumnutzungskonflikten eigene bzw. fremde Positionen unter Nutzung von Sachargumenten; HK2 beteiligen sich an Planungsaufgaben im Rahmen von Unterrichtsgängen.",
"seite": "S. 17-18",
"klassenstufe": "Jg. 5-6",
"sim_vorschlag": ["eu-werkstatt", "klima"],
"kompetenz_vorschlag": 13,
"begruendung": "Probehandeln in Raumnutzungskonflikten — Kern der EU-Werkstatt (Buergerbeteiligung)."
}
]
},
"niedersachsen_kerncurriculum_erdkunde_gymnasium": {
"quelle": "Niedersächsisches Kultusministerium: Kerncurriculum für das Gymnasium Schuljahrgänge 5-10 — Erdkunde. Hannover (NIBIS). Aktuelle Ausgabe.",
"url_primary": "https://cuvo.nibis.de/cuvo.php?p=download&upload=61",
"url_mirror": "https://caeci.de/files/seiten/erdkunde/kc%20Sek%201%20Ek.pdf",
"schulform": "Gymnasium",
"klassen": "5-10",
"anker": [
{
"code": "NI-FW-J10-Klima",
"kompetenzbereich": "Fachwissen",
"titel": "Klimazonen und Klimawandel (Schuljahrgang 10)",
"quote": "erklären Grundzüge der tropischen Zirkulation; erläutern Ursachen und Auswirkungen von Klimaveränderungen (Rückgriff auf erarbeitetes Fachwissen, z.B. über den Kohlenstoffdioxid-Kreislauf, aus den Fächern Chemie, Physik, Biologie); erläutern Anforderungen an nachhaltige Raumnutzungen im lokalen und globalen Kontext (z.B. bei Dürregefährdung, Übersiedlung, Übernutzung).",
"seite": "S. 12",
"klassenstufe": "Schuljahrgang 10 (Doppeljahrgang 9/10)",
"sim_vorschlag": ["klima", "klima-3d", "farmer"],
"kompetenz_vorschlag": 1,
"begruendung": "Direkter Klimawandel-Anker + tropische Zirkulation als Klimazonen-Grundlage."
},
{
"code": "NI-FW-J8-Naturgefahren",
"kompetenzbereich": "Fachwissen",
"titel": "Naturgefahren und Naturlandschaften (Schuljahrgang 8)",
"quote": "erklären Naturlandschaften im Zusammenhang erdgeschichtlicher Vorgänge als Ergebnis endogener Prozesse (Plattentektonik, Vulkanismus, Erdbeben) — exogener Prozesse (Verwitterung, Erosion, Sedimentation); erläutern die Notwendigkeit schadens- und risikomindernder Maßnahmen bei natürlichen Vorgängen (z.B. Vulkanismus, Erdbeben, Tsunami).",
"seite": "S. 12",
"klassenstufe": "Schuljahrgang 8 (Doppeljahrgang 7/8)",
"sim_vorschlag": ["fluss", "heli", "sonnensystem"],
"kompetenz_vorschlag": 2,
"begruendung": "Schadens-/risikomindernde Massnahmen = Hochwasserschutz-Logik; Plattentektonik = sonnensystem peripher."
},
{
"code": "NI-FW-J10-Mobilitaet",
"kompetenzbereich": "Fachwissen",
"titel": "Mobilität, Migration und Wirtschaftsräume (Schuljahrgang 10)",
"quote": "erläutern Ursachen und raumstrukturelle Auswirkungen von Mobilität und Migration (z.B. räumliche Disparitäten, Bevölkerungsentwicklung, Megastädte); erläutern regionale und globale wirtschaftsräumliche Verflechtungen in Landwirtschaft (z.B. Veredlungswirtschaft, Agrobusiness) und Industrie (z.B. Ruhrgebiet, Manufacturing Belt, Luft- und Raumfahrtstandorte, Automobilstandorte, Energieverbünde).",
"seite": "S. 13",
"klassenstufe": "Schuljahrgang 10",
"sim_vorschlag": ["logistik", "busfahrt", "weltkueche"],
"kompetenz_vorschlag": 7,
"begruendung": "Globale wirtschaftsraeumliche Verflechtungen = Logistik-Kern; Agrobusiness = weltkueche-Ueberlapp."
},
{
"code": "NI-RO-J6-Karte",
"kompetenzbereich": "Räumliche Orientierung",
"titel": "Orientierung mit Karte und Gradnetz (Schuljahrgang 6)",
"quote": "orientieren sich im Raum und auf Karten anhand der Himmelsrichtungen (Sonnenstand, Kompass, natürliche Gegebenheiten); berechnen Entfernungen mit Hilfe des Maßstabs (Absprache mit dem Fach Mathematik); lokalisieren geographische Objekte im Nahraum, in Deutschland und Europa im Gradnetz und auf Karten; benennen in stummen Karten Gewässer, Gebirge, Großlandschaften, Staaten und Siedlungen.",
"seite": "S. 14",
"klassenstufe": "Schuljahrgang 6 (Doppeljahrgang 5/6)",
"sim_vorschlag": ["heli", "busfahrt", "logistik"],
"kompetenz_vorschlag": 6,
"begruendung": "Karten + Gradnetz + Entfernungen = kartenkompetenz-logistik; Himmelsrichtungen mit Kompass = heli."
},
{
"code": "NI-RO-J10-Massstaebe",
"kompetenzbereich": "Räumliche Orientierung",
"titel": "Maßstabsebenen, Luftbilder, GPS (Schuljahrgang 10)",
"quote": "orientieren sich gegebenenfalls auch mit GPS; vergleichen Entfernungen und räumliche Beziehungen auf unterschiedlichen Maßstabsebenen; lokalisieren geographische Objekte in Luftbildern und Satellitenaufnahmen; lokalisieren Regionen unterschiedlichen Entwicklungsstandes.",
"seite": "S. 14",
"klassenstufe": "Schuljahrgang 10",
"sim_vorschlag": ["heli", "logistik"],
"kompetenz_vorschlag": 6,
"begruendung": "GPS + Luftbilder + Massstabsebenen = kartenkompetenz-logistik fortgeschritten; Heli-Sim nutzt 3D-Satellitenaufnahme."
},
{
"code": "NI-Beurt-J8-Klima",
"kompetenzbereich": "Beurteilung/Bewertung",
"titel": "Tragweite menschlicher Eingriffe (Schuljahrgang 8)",
"quote": "beurteilen Nutzungsmöglichkeiten und Lebensbedingungen in verschiedenen Klimazonen; bewerten die Tragweite menschlicher Eingriffe in natürliche Systeme (z.B. Anpflanzung von Eukalyptusbäumen im Mittelmeerraum, Bewässerung, Flussbegradigung, Rodung); nennen Vor- und Nachteile des Lebens in von Naturkatastrophen bedrohten Siedlungsräumen.",
"seite": "S. 17",
"klassenstufe": "Schuljahrgang 8",
"sim_vorschlag": ["fluss", "farmer", "klima"],
"kompetenz_vorschlag": 14,
"begruendung": "Klimazonen-Nutzung = landwirtschaft-klimazonen; Flussbegradigung = naturgefahren-hochwasser sekundaer."
},
{
"code": "NI-Beurt-J10-Welt",
"kompetenzbereich": "Beurteilung/Bewertung",
"titel": "Welthandel, Entwicklung, Klimaprognosen (Schuljahrgang 10)",
"quote": "bewerten geographisch relevante Sachverhalte und Prozesse (z.B. Entwicklungshilfe / wirtschaftliche Zusammenarbeit, Welthandel, Ressourcennutzung) in differenzierender Weise; nehmen Stellung zu Prognosen (z.B. Klimawandel, demographische Entwicklungen); erörtern Möglichkeiten nachhaltiger Nutzung (z.B. Landwirtschaft, Energie, Tourismus).",
"seite": "S. 17-18",
"klassenstufe": "Schuljahrgang 10",
"sim_vorschlag": ["weltkueche", "klima", "eu-werkstatt", "energiemanager"],
"kompetenz_vorschlag": 13,
"begruendung": "Welthandel-Bewertung + Klima-Prognosen — politisch-bewertend = eu-politische-beteiligung; Energie = energieversorgung-speicherung."
}
]
},
"bayern_lehrplanplus": {
"quelle": "Bayerisches Staatsministerium für Unterricht und Kultus: LehrplanPLUS — Fachlehrpläne Geographie Gymnasium und Realschule.",
"url_basis": "https://www.lehrplanplus.bayern.de/",
"anker": [
{
"code": "BY-Gym-Geo5-LB1",
"titel": "Geographie 5 Gymnasium — Lernbereich 1: Geographische Arbeitstechniken",
"quote": "Schülerinnen und Schüler arbeiten grundlegende Informationen aus verschiedenen Kartenarten und dem Atlas heraus; bestimmen Himmelsrichtungen, Lage im Gradnetz, Maßstab und Distanzen; unterscheiden topografische, physische und thematische Karten.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/5/geographie",
"schulform": "Gymnasium",
"klassenstufe": "5",
"sim_vorschlag": ["heli", "busfahrt", "logistik"],
"kompetenz_vorschlag": 6,
"begruendung": "Direkter Match zu kartenkompetenz-logistik in der Einstiegsklasse."
},
{
"code": "BY-Gym-Geo5-LB3",
"titel": "Geographie 5 Gymnasium — Lernbereich 3: Naturräume in Bayern und Deutschland",
"quote": "beschreiben überblicksartig die naturräumliche Gliederung Bayerns und Deutschlands; Alpen und Alpenvorland: Entstehung und Überformung, Naturpotenzial und touristische Nutzung; Mittelgebirge: Entstehung von Bruchschollengebirgen oder Stufenländern, Landschaftsschutz.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/5/geographie",
"schulform": "Gymnasium",
"klassenstufe": "5",
"sim_vorschlag": ["heli", "fluss"],
"kompetenz_vorschlag": 3,
"begruendung": "Alpen-Entstehung + touristische Nutzung = karten-navigation-alpen; Heli-Sim Bergrettung Alpen."
},
{
"code": "BY-Gym-Geo5-LB5",
"titel": "Geographie 5 Gymnasium — Lernbereich 5: Städtische Räume in Bayern und Deutschland",
"quote": "verorten Verdichtungsräume und kennen die politische Gliederung Bayerns und Deutschlands; orientieren sich mit geeigneten Karten in städtischen Räumen.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/5/geographie",
"schulform": "Gymnasium",
"klassenstufe": "5",
"sim_vorschlag": ["busfahrt"],
"kompetenz_vorschlag": 4,
"begruendung": "Verdichtungsraeume + staedtische Orientierung = stadtplanung-raum; Busfahrt deckt Stadt-Stationen."
},
{
"code": "BY-Gym-Geo7-LB1",
"titel": "Geographie 7 Gymnasium — Lernbereich 1: Geographische Arbeitstechniken",
"quote": "werten physische und thematische Karten aus und fertigen eigene Kartenskizzen an; analysieren und zeichnen Klimadiagramme sowie einfache Liniendiagramme; nutzen digitale Geomedien, um geographische Sachverhalte strukturiert darzustellen.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/7/geographie",
"schulform": "Gymnasium",
"klassenstufe": "7",
"sim_vorschlag": ["klima", "farmer", "heli"],
"kompetenz_vorschlag": 6,
"begruendung": "Klimadiagramme + thematische Karten = Kartenkompetenz; klima/farmer arbeiten mit Klimadiagrammen."
},
{
"code": "BY-Gym-Geo7-LB2",
"titel": "Geographie 7 Gymnasium — Lernbereich 2: Einheit und Vielfalt in Europa",
"quote": "ordnen Staaten und Regionen Europas einzelnen Teilräumen richtig zu; stellen die europäische Idee in Grundzügen dar und reflektieren grundlegende Auswirkungen; erläutern beispielhaft die politische, wirtschaftliche und kulturelle Zusammenarbeit in Europa.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/7/geographie",
"schulform": "Gymnasium",
"klassenstufe": "7",
"sim_vorschlag": ["busfahrt", "logistik", "eu-werkstatt"],
"kompetenz_vorschlag": 5,
"begruendung": "Staaten/Regionen Europas zuordnen = raeumliche-orientierung-europa direkt; europaeische Idee + politisch = eu-werkstatt."
},
{
"code": "BY-Gym-Geo7-LB3",
"titel": "Geographie 7 Gymnasium — Lernbereich 3: Naturgeographie Europas im Überblick",
"quote": "arbeiten Kriterien für eine naturräumliche Gliederung Europas heraus; stellen die Grundzüge des Klimas und der Vegetation in Europa dar und zeigen Zusammenhänge; erläutern den Zusammenhang zwischen Plattengrenzen, Vulkanismus und Erdbeben.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/7/geographie",
"schulform": "Gymnasium",
"klassenstufe": "7",
"sim_vorschlag": ["klima", "farmer", "sonnensystem"],
"kompetenz_vorschlag": 14,
"begruendung": "Klima + Vegetation Europa = landwirtschaft-klimazonen Europa-Fokus."
},
{
"code": "BY-Gym-Geo7-LB5",
"titel": "Geographie 7 Gymnasium — Lernbereich 5: Metropolen und Verdichtungsräume in Europa",
"quote": "erläutern Merkmale, Strukturen und Herausforderungen von Metropolen; erklären und vergleichen die Bedeutung von Standortfaktoren unterschiedlicher Branchen.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/7/geographie",
"schulform": "Gymnasium",
"klassenstufe": "7",
"sim_vorschlag": ["busfahrt", "logistik"],
"kompetenz_vorschlag": 4,
"begruendung": "Europaeische Metropolen + Standortfaktoren = stadtplanung-raum auf EU-Ebene; Busfahrt-Stadt-Stationen."
},
{
"code": "BY-Gym-Geo10-LB2",
"titel": "Geographie 10 Gymnasium — Lernbereich 2: Leben in der Einen Welt",
"quote": "vergleichen Lebensrealitäten von Kindern und Jugendlichen in verschiedenen Ländern niedrigen Entwicklungsstandes; charakterisieren anhand unterschiedlicher kartografischer Darstellungen und Statistiken Regionen unterschiedlichen Entwicklungsstandes; nehmen kritisch Stellung zu gängigen Indikatoren zur Bestimmung des Entwicklungsstandes; stellen Merkmale und Probleme von Ländern mit niedrigem Entwicklungsstand dar.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/10/geographie",
"schulform": "Gymnasium",
"klassenstufe": "10",
"sim_vorschlag": ["weltkueche", "farmer"],
"kompetenz_vorschlag": null,
"begruendung": "Eine-Welt-Perspektive + Entwicklungsstand — kein 1:1-Match. Empfehlung: neue Plattform-Kompetenz 'welternaehrung-entwicklung' oder als zentrale Inhaltsdimension der weltkueche-Sim explizit machen."
},
{
"code": "BY-Gym-Geo10-LB4",
"titel": "Geographie 10 Gymnasium — Lernbereich 4: Klima im Wandel",
"quote": "erschließen die Ursachen für den zunehmenden anthropogenen Treibhauseffekt; beurteilen Folgen des Klimawandels auf unterschiedlichen Maßstabsebenen und stellen Anpassungsstrategien dar. Inhalte: Folgen des globalen Klimawandels im Überblick sowie Wetter-/Witterungsextreme und Klimaflüchtlinge.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/10/geographie",
"schulform": "Gymnasium",
"klassenstufe": "10",
"sim_vorschlag": ["klima", "klima-3d"],
"kompetenz_vorschlag": 1,
"begruendung": "Anthropogener Treibhauseffekt + Klimaanpassung = klimawandel-Kern. Klimafluechtlinge ergaenzt durch klima-3d Geflutet-Szenario."
},
{
"code": "BY-Gym-Geo10-LB6",
"titel": "Geographie 10 Gymnasium — Lernbereich 6: Afrika südlich der Sahara",
"quote": "stellen am Beispiel der Desertifikation die Fragilität von Ökosystemen dar; erörtern nachhaltige Nutzungs- und Entwicklungskonzepte; bewerten an einem konkreten Fallbeispiel Möglichkeiten nachhaltiger Entwicklung. Inhalte: Desertifikation in der Sahelzone: Ursachen, Folgen und Gegenmaßnahmen; ausländische Direktinvestitionen.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/10/geographie",
"schulform": "Gymnasium",
"klassenstufe": "10",
"sim_vorschlag": ["farmer", "klima"],
"kompetenz_vorschlag": 14,
"begruendung": "Desertifikation = Klimazone Sahelzone = landwirtschaft-klimazonen direkt."
},
{
"code": "BY-Gym-Geo10-LB7",
"titel": "Geographie 10 Gymnasium — Lernbereich 7: Mittel-/Südamerika",
"quote": "analysieren regionale und globale Folgen menschlicher Eingriffe in Naturräume; erörtern nachhaltige Konzepte der Raumerschließung und -nutzung; überprüfen an geeigneten Raumbeispielen die wirtschaftliche Integration in den globalen Markt. Inhalte: Amazonien: Ursachen und Folgen der Abholzung; Plantagenwirtschaft und Ferntourismus.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/10/geographie",
"schulform": "Gymnasium",
"klassenstufe": "10",
"sim_vorschlag": ["farmer", "weltkueche", "klima"],
"kompetenz_vorschlag": 14,
"begruendung": "Plantagenwirtschaft + Abholzung = landwirtschaft-klimazonen tropische Zone."
},
{
"code": "BY-Rs-Geo7-LB-Klima",
"titel": "Geographie 7 Realschule — Lernbereich: Planetarische Grundlagen im Zusammenhang mit Klima und Vegetation",
"quote": "Erklären planetarischer Grundlagen für unterschiedliche Beleuchtungsverhältnisse und deren Auswirkungen wie Zeitzonen skizzieren; wetterrelevante Vorgänge in der Atmosphäre beschreiben; Wechselbeziehungen zwischen Vegetation und Klima erläutern zur Gliederung der Erde in Geozonen; Klimadiagramme analysieren und räumlich zuordnen. Inhalte: Größe und Gestalt der Erde; Neigung zur Umlaufbahn, Erdrotation (Tag/Nacht, Zeitzonen), Erdrevolution (Jahreszeiten); Klima- und Vegetationszonen der Erde.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/lernbereich/66374",
"schulform": "Realschule",
"klassenstufe": "7",
"sim_vorschlag": ["sonnensystem", "klima", "farmer"],
"kompetenz_vorschlag": 12,
"begruendung": "Erdrotation/Revolution + Beleuchtungszonen + Zeitzonen = erdmechanik-klimazonen direkt — Sonnensystem-Sim deckt alles. Klimadiagramme = klima/farmer Bruecke."
},
{
"code": "BY-Rs-Geo8-LB1",
"titel": "Geographie 8 Realschule — Lernbereich 1: Doppelkontinent Amerika",
"quote": "1.1 beschreiben die physisch-geographischen sowie politischen Strukturen; analysieren an einem Beispiel die Verwundbarkeit. 1.3 Landwirtschaft, Rohstoffe und ökologische Verwundbarkeit: bewerten an je einem Beispiel aus Nord- und Südamerika ökologische Besonderheiten; reflektieren, dass ihr Konsumverhalten Auswirkungen auf Produktionsbedingungen hat.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/realschule/8/geographie",
"schulform": "Realschule",
"klassenstufe": "8",
"sim_vorschlag": ["farmer", "weltkueche"],
"kompetenz_vorschlag": 14,
"begruendung": "Landwirtschaft Nord-/Suedamerika + Konsum-Wirkung = landwirtschaft-klimazonen + weltkueche Klimabilanz."
},
{
"code": "BY-Rs-Geo8-LB4",
"titel": "Geographie 8 Realschule — Lernbereich 4: Globale Verflechtungen im Alltag",
"quote": "stellen wirtschaftliche Verflechtungen anhand der Produktion von zwei unterschiedlichen Konsumgütern dar; beschreiben und bewerten deren Produktionskette unter ökonomischen, ökologischen und sozialen Gesichtspunkten; reflektieren ihr Konsumverhalten; beschreiben Indikatoren für die Bewertung des Entwicklungsstandes von Staaten; erörtern ihre Möglichkeiten als Verbraucher, auf die Einhaltung nachhaltiger Standards einzuwirken.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/realschule/8/geographie",
"schulform": "Realschule",
"klassenstufe": "8",
"sim_vorschlag": ["weltkueche", "logistik", "busfahrt"],
"kompetenz_vorschlag": 7,
"begruendung": "Produktionskette + Konsumreflexion = wirtschaft-logistikverstaendnis; weltkueche-Klimabilanz-Bezug."
},
{
"code": "BY-Rs-Geo9-LB-Klima",
"titel": "Geographie 9 Realschule — Lernbereich Klima und Klimawandel (ca. 10 Std.)",
"quote": "das komplexe Zusammenspiel der Klimafaktoren anhand von Raumbeispielen aus Deutschland und Europa erklären und vergleichen; das Phänomen, die Ursachen und Auswirkungen des globalen Klimawandels beschreiben und die Rolle menschlicher Einflüsse analysieren; zu Klimawandelthemen materialgestützt aus unterschiedlichen Perspektiven Stellung nehmen; lokale und globale Maßnahmen zur Eindämmung des Klimawandels diskutieren; meteorologisch bedingte Naturgefahren und Extremereignisse analysieren.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/lernbereich/66557",
"schulform": "Realschule",
"klassenstufe": "9",
"sim_vorschlag": ["klima", "klima-3d", "energiemanager"],
"kompetenz_vorschlag": 1,
"begruendung": "Klimawandel + Klimapolitik + Extremereignisse (Hochwasser explizit als Inhalt) = klimawandel + naturgefahren-hochwasser sekundaer."
},
{
"code": "BY-Rs-Geo9-LB-Ernaehrung",
"titel": "Geographie 9 Realschule — Lernbereich Landwirtschaft, Ernährung, Boden",
"quote": "Themen sind konventionelle vs. ökologische Landwirtschaft, Wirkungsgefüge zwischen Landwirtschaft und Umwelt, sowie Welternährungssituation und Nahrungsmittelverfügbarkeit. Schüler ordnen Hunger- und Ernährungskrisen naturgeographischen und anthropogenen Ursachen zu.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/realschule/9/geographie",
"schulform": "Realschule",
"klassenstufe": "9",
"sim_vorschlag": ["farmer", "weltkueche"],
"kompetenz_vorschlag": 14,
"begruendung": "Welternaehrungssituation + Landwirtschaft = direkter Anker fuer Farmer + Weltkueche. Bedarfsempfehlung: neue Plattform-Kompetenz 'welternaehrung'."
},
{
"code": "BY-Rs-Geo9-LB-Grenzen",
"titel": "Geographie 9 Realschule — Lernbereich Grenzen im Wandel",
"quote": "Behandelt Europäische Union, Begriff und Auswirkungen der Globalisierung in Umwelt, Wirtschaft, Kommunikation und Kultur sowie Global Player und Grenzentstehung.",
"url": "https://www.lehrplanplus.bayern.de/fachlehrplan/realschule/9/geographie",
"schulform": "Realschule",
"klassenstufe": "9",
"sim_vorschlag": ["eu-werkstatt", "logistik", "busfahrt"],
"kompetenz_vorschlag": 13,
"begruendung": "Europaeische Union + Globalisierung = eu-politische-beteiligung primaer; raeumliche-orientierung-europa sekundaer."
}
]
},
"luecken_und_offene_fragen": [
{
"luecke": "Bayern Gymnasium 8 und 9 (G9-Geographie)",
"details": "WebFetch lieferte fuer https://www.lehrplanplus.bayern.de/fachlehrplan/gymnasium/8/geographie und /9/geographie nur die Startseite, nicht den Lernbereich-Inhalt. Workaround: ueber die Realschule 8/9 abgedeckt (sehr aehnliche Themen) plus Lernbereich 'Klima und Klimawandel' (66557) und 'Planetarische Grundlagen' (66374). Fuer Gym G8/G9 manuell nachpruefen."
},
{
"luecke": "Hauswirtschaft / Verbraucherbildung / AWT in Bundeslaendern",
"details": "Nicht systematisch recherchiert — fuer Weltkueche-Sim relevant, aber Faecher-Bezeichnungen variieren stark (AWT BY, WiB BW, WiB NRW Hauptschule, Verbraucherbildung Berlin etc.). Empfehlung: separater Mini-Auftrag fuer Hauswirtschaft/AWT-Anker."
},
{
"luecke": "Politik/SoWi/Wirtschaft fuer EU-Werkstatt",
"details": "Wird in NRW als 'Wirtschaft-Politik' (KLP separat), in Bayern als Sozialkunde 10 (LehrplanPLUS) und in Niedersachsen als 'Politik-Wirtschaft' angeboten. Fuer eu-werkstatt-Sim wertvoll. Nicht recherchiert in diesem Durchgang."
},
{
"luecke": "Sachunterricht 4. Klasse",
"details": "Als optionaler Bonus angefragt, aber nicht recherchiert — Sachunterricht-Lehrplaene sind extrem bundeslaender-spezifisch und decken nur 9-10-Jaehrige (vor Sek I). Fuer den GeoGraSim-Hauptscope 10-15 J. nicht prioritaer."
},
{
"luecke": "Hessen, Baden-Wuerttemberg, Berlin/Brandenburg, Rheinland-Pfalz, Sachsen",
"details": "Existierende Anker in der DB (id 1085, 1089, 1106, 1109, 1110, 1147) verweisen auf diese Laender, sind aber stichprobenhaft. Eine systematische Recherche pro Land wuerde den Scope dieser Aufgabe sprengen. Empfehlung: nach Atlas-Review der hier dokumentierten Anker entscheiden, ob Hessen+BW+BE/BB als 'big four' Sued/Sued-West-Cluster ergaenzt werden."
},
{
"luecke": "Plattform-Kompetenz 'Welternaehrung / Disparitaeten'",
"details": "Drei zentrale Lehrplan-Anker (NRW IF7, BY-Gym-Geo10-LB2, BY-Rs-Geo9-LB-Ernaehrung) thematisieren Welternaehrung, Hungerkrisen und Entwicklungs-Disparitaeten als Kernthema. In den 14 GeoGraSim-Kompetenzen gibt es dafuer keinen direkten Anker — am naechsten kommt landwirtschaft-klimazonen (#14). Empfehlung an Thomas: entweder #14 explizit um 'Welternaehrung und Disparitaeten' erweitern oder neue Kompetenz #15 'welternaehrung-disparitaeten' anlegen — passend fuer Weltkueche-Sim als Primaer-Anker und Farmer-Sim als Sekundaer-Anker."
}
]
}
File diff suppressed because it is too large Load Diff
@@ -1,849 +0,0 @@
HTML geschrieben: 50432 Bytes
">
<head>
<meta charset="UTF-8">
<title>Lehrplan-Coverage Phase 3 · GeoGraSim</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',system-ui,sans-serif;background:#f5f2eb;color:#2a2a2a;line-height:1.5;padding:24px;max-width:1400px;margin:0 auto}
h1{color:#1f4e5a;font-size:1.6rem;margin-bottom:4px}
.sub{font-size:.82rem;color:#8a8a8a;margin-bottom:18px}
h2{color:#1f4e5a;font-size:1.15rem;margin:28px 0 10px;padding-bottom:6px;border-bottom:2px solid #4a7c8a;display:flex;align-items:center;gap:8px}
h3{color:#4a7c8a;font-size:.98rem;margin:18px 0 8px}
table{width:100%;border-collapse:collapse;font-size:.84rem;background:#fff;border-radius:6px;overflow:hidden;margin-bottom:10px}
th,td{text-align:left;padding:7px 10px;border-bottom:1px solid #e0ddd4;vertical-align:top}
th{background:#1f4e5a;color:#fff;font-weight:600;font-size:.74rem;text-transform:uppercase;letter-spacing:.04em}
tr:hover{background:#fafaf5}
tr:last-child td{border-bottom:none}
td.num,th.num{text-align:right;font-variant-numeric:tabular-nums;font-weight:600}
td.num .delta{color:#4a7c4e;font-size:.78em;margin-left:4px}
td.num .delta.zero{color:#bbb}
td.zero{color:#cfcfcf}
code{background:#f5f2eb;padding:2px 6px;border-radius:3px;font-family:'JetBrains Mono',Consolas,monospace;font-size:.85em}
a{color:#1f4e5a}
.badge{display:inline-block;font-size:.68rem;font-weight:700;padding:2px 7px;border-radius:9999px;margin-right:4px}
.b-new{background:#e3e9d6;color:#4a6b3f}
.b-existing{background:#d6e3e9;color:#1f4e5a}
.b-country-at{background:#fde0db;color:#9c4d2e}
.b-country-ch{background:#fff7e0;color:#8a6516}
.b-country-de{background:#d6e3e9;color:#1f4e5a}
.b-country-li{background:#e0ddd4;color:#666}
.top-nav{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:10px 14px;margin-bottom:18px;font-size:.86rem;display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.top-nav a{text-decoration:none;padding:5px 11px;border-radius:6px;color:#1f4e5a}
.top-nav a:hover{background:#f5f2eb}
.top-nav a.active{background:#1f4e5a;color:#fff}
.info-box{background:#fff7e0;border-left:4px solid #d2a24c;padding:12px 16px;margin:14px 0;border-radius:0 6px 6px 0;font-size:.88rem}
.stat-cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(180px,1fr));gap:12px;margin-bottom:14px}
.stat-card{background:#fff;border-radius:8px;padding:12px 16px;border:1px solid #e0ddd4}
.stat-card .label{font-size:.72rem;text-transform:uppercase;color:#888;font-weight:700;letter-spacing:.04em}
.stat-card .value{font-size:1.8rem;font-weight:800;color:#1f4e5a;line-height:1.1;margin-top:2px}
.stat-card .delta{font-size:.85rem;color:#4a7c4e;font-weight:600}
.sim-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(280px,1fr));gap:14px;margin-top:14px}
.sim-card{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:14px 16px}
.sim-card h4{color:#1f4e5a;font-size:.98rem;margin-bottom:8px;display:flex;align-items:center;gap:8px}
.sim-card .counts{font-size:.78rem;color:#666;margin-bottom:10px}
.sim-card .counts b{color:#1f4e5a}
.sim-card ul{list-style:none;padding:0;font-size:.84rem}
.sim-card li{padding:6px 0;border-bottom:1px dotted #e0ddd4}
.sim-card li:last-child{border-bottom:none}
.gap-list .gap-item{background:#fff;border:1px solid #e0ddd4;border-left:4px solid #d2a24c;border-radius:0 6px 6px 0;padding:12px 16px;margin-bottom:10px}
.gap-item h4{color:#1f4e5a;font-size:.95rem;margin-bottom:6px}
.gap-item .gap-line{font-size:.84rem;margin-top:4px}
.gap-item .gap-line b{color:#1f4e5a}
.gap-item .status{display:inline-block;font-size:.72rem;font-weight:700;padding:3px 10px;border-radius:9999px;background:#fff7e0;color:#8a6516;margin-top:6px}
.gap-item .status.full{background:#e3e9d6;color:#4a6b3f}
.gap-item .status.partial{background:#fde0db;color:#9c4d2e}
.matrix-table th.col-sim,.matrix-table td.col-sim{background:#fafaf5;font-weight:600;color:#1f4e5a}
.matrix-table td.cell{text-align:center;font-variant-numeric:tabular-nums}
.matrix-table td.cell.zero{color:#cfcfcf}
.matrix-table td.cell .new{display:inline-block;color:#4a7c4e;font-weight:700;font-size:.78em;margin-left:3px}
details{background:#fff;border:1px solid #e0ddd4;border-radius:6px;margin-bottom:8px}
details summary{padding:10px 14px;cursor:pointer;font-weight:600;color:#1f4e5a;font-size:.92rem}
details[open] summary{border-bottom:1px solid #e0ddd4}
details > div{padding:0 14px 12px}
.note{font-size:.78rem;color:#888;font-style:italic;margin-top:6px}
</style>
</head>
<body>
<nav class="top-nav">
<strong>Entwurfswerkzeug</strong>
<a href="index.html">Uebersicht</a>
<a href="../entwurf.html">Entwurf</a>
<a href="../review.html">Review</a>
<a href="accounts.html">Accounts</a>
<a href="standards.html">Standards</a>
<a href="lehrplan-uebersicht.html" class="active">Lehrplan-Coverage</a>
<a href="../../App/admin-sitemap.html" target="_blank">Sitemap</a>
</nav>
<h1>Lehrplan-Coverage Phase 3</h1>
<p class="sub">Stand: 2026-06-08 · Synthese-Snapshot AT/CH/DE/LI · Quelle: <code>.dontDeploy/entwurfswerkzeug/lehrplan-synthese-phase3.json</code></p>
<div style="background:#fff;border-radius:8px;padding:14px 18px;margin:14px 0;border:1px solid #e0ddd4">
<h3 style="color:#1f4e5a;margin:0 0 8px;font-size:1rem">📖 Was du auf dieser Seite siehst — kurz erklärt</h3>
<ul style="font-size:.9rem;line-height:1.6;margin:0;padding-left:1.4em;color:#3a3a3a">
<li><b>Anker</b> = ein wörtlicher Verweis aus einem Schul-Lehrplan auf eines unserer Sim-Themen.
Beispiel: AT-Lehrplan GW Kompetenz 3.3 sagt wörtlich „Import/Export — Außenwirtschaft Österreichs". Das ist ein Anker für unsere Busfahrt/Logistik/Weltküche-Sims.
Jeder Anker hat Land · Fach · Klassenstufe · wörtliches Zitat · Quelle-URL.</li>
<li><b>Plattform-Kompetenz</b> = einer von 14 (mit der neuen 15) intern definierten Sammelbegriffen wie „Klimawandel", „Welthandel", „Kartenkompetenz". Jede Sim ist mehreren zugeordnet. Anker werden indirekt über die Plattform-Kompetenz mit der Sim verknüpft.</li>
<li><b>Coverage / Abdeckung</b> = wie viele Anker wir pro Sim und pro Land haben. Wir zeigen <b>keine Prozente</b>, weil es keine geschlossene Soll-Liste „Lehrplan = 100 Anker" gibt. Stattdessen <b>Ampel</b>:
<span style="background:#e3e9d6;color:#4a6b3f;padding:2px 8px;border-radius:9999px;font-weight:700;font-size:.8em">🟢 gut ≥ 6</span>
<span style="background:#fff7e0;color:#a37e1a;padding:2px 8px;border-radius:9999px;font-weight:700;font-size:.8em">🟡 ok 35</span>
<span style="background:#fde0db;color:#9c4d2e;padding:2px 8px;border-radius:9999px;font-weight:700;font-size:.8em">🟠 dünn 12</span>
<span style="background:#fbcfcf;color:#9c2e2e;padding:2px 8px;border-radius:9999px;font-weight:700;font-size:.8em">🔴 leer 0</span></li>
<li><b>Bestand vs. neu:</b> „Bestand" = was schon in der DB war. „Neu" = was Phase-3-Recherche zusätzlich vorschlägt (noch nicht in DB — muss erst per SQL-Migration übernommen werden).</li>
</ul>
</div>
<div class="info-box">
<b>Quellen:</b> Bestand-Zahlen aus DB (<code>lehrplan_anchors</code>, 14 Plattform-Kompetenzen).
Neu-Zahlen aus Phase-2-Synthese: AT-RIS BGBl. II 1/2023 (BMBWF Sek I + VS), CH-LP21 (Sankt Gallen-Quelle <code>sg.lehrplan.ch</code>), DE-DGfG/NRW/Niedersachsen/Bayern (alles wörtlich aus PDFs extrahiert).
</div>
<h2>Gesamt-Statistik vor und nach Phase 3</h2>
<div class="stat-cards">
<div class="stat-card">
<div class="label">Anker AT (bestand &rarr; neu)</div>
<div class="value">103 &rarr; 134</div>
<div class="delta">+31 aus BGBl. II 1/2023</div>
</div>
<div class="stat-card">
<div class="label">Anker CH (bestand &rarr; neu)</div>
<div class="value">16 &rarr; 57</div>
<div class="delta">+41 aus LP21 (SG)</div>
</div>
<div class="stat-card">
<div class="label">Anker DE (bestand &rarr; neu)</div>
<div class="value">18 &rarr; 64</div>
<div class="delta">+46 DGfG/NRW/NI/BY</div>
</div>
<div class="stat-card">
<div class="label">Anker LI</div>
<div class="value">7 &rarr; 7</div>
<div class="delta" style="color:#888">unveraendert</div>
</div>
<div class="stat-card">
<div class="label">Total Anker</div>
<div class="value">144 &rarr; 262</div>
<div class="delta">+118 Anker</div>
</div>
<div class="stat-card">
<div class="label">Plattform-Kompetenzen</div>
<div class="value">14 &rarr; 15</div>
<div class="delta">+1 (welternaehrung-konsum-disparitaeten)</div>
</div>
</div>
<h2>Sim &times; Land Matrix</h2>
<p class="sub">Anker pro Sim und Land. Format: <code>bestand</code> mit <span style="color:#4a7c4e;font-weight:700">+neu</span>.</p>
<table class="matrix-table">
<thead>
<tr>
<th class="col-sim">Sim</th>
<th class="num">AT</th>
<th class="num">CH (SG)</th>
<th class="num">DE</th>
<th class="num">LI</th>
<th class="num">Sum bestand</th>
<th class="num">Sum neu</th>
</tr>
</thead>
<tbody>
<tr>
<td class="col-sim">Busfahrt</td>
<td class="cell ">16<span class="new">+17</span></td>
<td class="cell ">0<span class="new">+11</span></td>
<td class="cell ">0<span class="new">+18</span></td>
<td class="cell zero">0</td>
<td class="num">16</td>
<td class="num"><span class="delta">+46</span></td>
</tr>
<tr>
<td class="col-sim">Energiemanager</td>
<td class="cell ">22<span class="new">+5</span></td>
<td class="cell ">4<span class="new">+6</span></td>
<td class="cell ">5<span class="new">+2</span></td>
<td class="cell ">2</td>
<td class="num">33</td>
<td class="num"><span class="delta">+13</span></td>
</tr>
<tr>
<td class="col-sim">EU-Werkstatt</td>
<td class="cell ">14<span class="new">+6</span></td>
<td class="cell ">0<span class="new">+4</span></td>
<td class="cell ">0<span class="new">+9</span></td>
<td class="cell zero">0</td>
<td class="num">14</td>
<td class="num"><span class="delta">+19</span></td>
</tr>
<tr>
<td class="col-sim">Farmer</td>
<td class="cell ">32<span class="new">+17</span></td>
<td class="cell ">4<span class="new">+15</span></td>
<td class="cell ">5<span class="new">+16</span></td>
<td class="cell ">2</td>
<td class="num">43</td>
<td class="num"><span class="delta">+48</span></td>
</tr>
<tr>
<td class="col-sim">Fluss</td>
<td class="cell ">18<span class="new">+6</span></td>
<td class="cell ">8<span class="new">+6</span></td>
<td class="cell ">9<span class="new">+7</span></td>
<td class="cell ">4</td>
<td class="num">39</td>
<td class="num"><span class="delta">+19</span></td>
</tr>
<tr>
<td class="col-sim">Heli</td>
<td class="cell ">30<span class="new">+4</span></td>
<td class="cell ">8<span class="new">+6</span></td>
<td class="cell ">9<span class="new">+10</span></td>
<td class="cell ">3</td>
<td class="num">50</td>
<td class="num"><span class="delta">+20</span></td>
</tr>
<tr>
<td class="col-sim">Klima</td>
<td class="cell ">11<span class="new">+14</span></td>
<td class="cell ">4<span class="new">+8</span></td>
<td class="cell ">5<span class="new">+18</span></td>
<td class="cell ">2</td>
<td class="num">22</td>
<td class="num"><span class="delta">+40</span></td>
</tr>
<tr>
<td class="col-sim">Klima 3D</td>
<td class="cell ">11<span class="new">+10</span></td>
<td class="cell ">4<span class="new">+1</span></td>
<td class="cell ">5<span class="new">+7</span></td>
<td class="cell ">2</td>
<td class="num">22</td>
<td class="num"><span class="delta">+18</span></td>
</tr>
<tr>
<td class="col-sim">Logistik</td>
<td class="cell ">26<span class="new">+15</span></td>
<td class="cell ">0<span class="new">+12</span></td>
<td class="cell ">0<span class="new">+14</span></td>
<td class="cell zero">0</td>
<td class="num">26</td>
<td class="num"><span class="delta">+41</span></td>
</tr>
<tr>
<td class="col-sim">Sonnensystem</td>
<td class="cell ">32<span class="new">+2</span></td>
<td class="cell ">8<span class="new">+2</span></td>
<td class="cell ">9<span class="new">+7</span></td>
<td class="cell ">3</td>
<td class="num">52</td>
<td class="num"><span class="delta">+11</span></td>
</tr>
<tr>
<td class="col-sim">Weltkueche</td>
<td class="cell ">0<span class="new">+20</span></td>
<td class="cell ">0<span class="new">+12</span></td>
<td class="cell ">0<span class="new">+15</span></td>
<td class="cell zero">0</td>
<td class="num">0</td>
<td class="num"><span class="delta">+47</span></td>
</tr>
</tbody>
</table>
<h2>Plattform-Kompetenz &times; Land Matrix</h2>
<p class="sub">Anker pro Plattform-Kompetenz und Land.</p>
<table class="matrix-table">
<thead>
<tr>
<th class="col-sim">Kompetenz</th>
<th class="num">AT</th>
<th class="num">CH (SG)</th>
<th class="num">DE</th>
<th class="num">LI</th>
<th class="num">Sum bestand</th>
<th class="num">Sum neu</th>
</tr>
</thead>
<tbody>
<tr>
<td class="col-sim">Klimawandel verstehen und gestalten <br><span class="note"><code>klimawandel</code></span></td>
<td class="cell ">11<span class="new">+2</span></td>
<td class="cell ">4<span class="new">+3</span></td>
<td class="cell ">5<span class="new">+5</span></td>
<td class="cell ">2</td>
<td class="num">22</td>
<td class="num"><span class="delta">+10</span></td>
</tr>
<tr>
<td class="col-sim">Naturgefahren und Hochwasserschutz <br><span class="note"><code>naturgefahren-hochwasser</code></span></td>
<td class="cell ">10<span class="new">+1</span></td>
<td class="cell ">4<span class="new">+2</span></td>
<td class="cell ">5<span class="new">+3</span></td>
<td class="cell ">2</td>
<td class="num">21</td>
<td class="num"><span class="delta">+6</span></td>
</tr>
<tr>
<td class="col-sim">Kartenkompetenz und alpine Geografie <br><span class="note"><code>karten-navigation-alpen</code></span></td>
<td class="cell ">13</td>
<td class="cell ">4<span class="new">+2</span></td>
<td class="cell ">4<span class="new">+3</span></td>
<td class="cell ">1</td>
<td class="num">22</td>
<td class="num"><span class="delta">+5</span></td>
</tr>
<tr>
<td class="col-sim">Stadtplanung und Raumordnung <br><span class="note"><code>stadtplanung-raum</code></span></td>
<td class="cell ">8<span class="new">+2</span></td>
<td class="cell ">4<span class="new">+4</span></td>
<td class="cell ">4<span class="new">+4</span></td>
<td class="cell ">2</td>
<td class="num">18</td>
<td class="num"><span class="delta">+10</span></td>
</tr>
<tr>
<td class="col-sim">Räumliche Orientierung in Europa <br><span class="note"><code>raeumliche-orientierung-europa</code></span></td>
<td class="cell ">6<span class="new">+1</span></td>
<td class="cell ">0<span class="new">+2</span></td>
<td class="cell ">0<span class="new">+2</span></td>
<td class="cell zero">0</td>
<td class="num">6</td>
<td class="num"><span class="delta">+5</span></td>
</tr>
<tr>
<td class="col-sim">Kartenkompetenz im europäischen Maßstab <br><span class="note"><code>kartenkompetenz-logistik</code></span></td>
<td class="cell ">5<span class="new">+1</span></td>
<td class="cell ">0<span class="new">+2</span></td>
<td class="cell ">0<span class="new">+6</span></td>
<td class="cell zero">0</td>
<td class="num">5</td>
<td class="num"><span class="delta">+9</span></td>
</tr>
<tr>
<td class="col-sim">Wirtschafts- und Logistikverständnis <br><span class="note"><code>wirtschaft-logistikverstaendnis</code></span></td>
<td class="cell ">5<span class="new">+4</span></td>
<td class="cell ">0<span class="new">+5</span></td>
<td class="cell ">0<span class="new">+4</span></td>
<td class="cell zero">0</td>
<td class="num">5</td>
<td class="num"><span class="delta">+13</span></td>
</tr>
<tr>
<td class="col-sim">Planungs- und Entscheidungskompetenz <br><span class="note"><code>planungs-entscheidungskompetenz</code></span></td>
<td class="cell ">3</td>
<td class="cell ">0<span class="new">+1</span></td>
<td class="cell zero">0</td>
<td class="cell zero">0</td>
<td class="num">3</td>
<td class="num"><span class="delta">+1</span></td>
</tr>
<tr>
<td class="col-sim">Verkehrserziehung und Sicherheitsbewusstsein <br><span class="note"><code>verkehrserziehung-sicherheit</code></span></td>
<td class="cell ">3<span class="new">+1</span></td>
<td class="cell ">0<span class="new">+2</span></td>
<td class="cell zero">0</td>
<td class="cell zero">0</td>
<td class="num">3</td>
<td class="num"><span class="delta">+3</span></td>
</tr>
<tr>
<td class="col-sim">Systemisches Denken <br><span class="note"><code>systemisches-denken</code></span></td>
<td class="cell ">4<span class="new">+2</span></td>
<td class="cell zero">0</td>
<td class="cell ">0<span class="new">+1</span></td>
<td class="cell zero">0</td>
<td class="num">4</td>
<td class="num"><span class="delta">+3</span></td>
</tr>
<tr>
<td class="col-sim">Energieversorgung und Energiespeicherung <br><span class="note"><code>energieversorgung-speicherung</code></span></td>
<td class="cell ">11<span class="new">+2</span></td>
<td class="cell ">0<span class="new">+4</span></td>
<td class="cell zero">0</td>
<td class="cell zero">0</td>
<td class="num">11</td>
<td class="num"><span class="delta">+6</span></td>
</tr>
<tr>
<td class="col-sim">Erdmechanik, Klimazonen und Astronomie <br><span class="note"><code>erdmechanik-klimazonen</code></span></td>
<td class="cell ">8<span class="new">+1</span></td>
<td class="cell ">0<span class="new">+2</span></td>
<td class="cell ">0<span class="new">+3</span></td>
<td class="cell zero">0</td>
<td class="num">8</td>
<td class="num"><span class="delta">+6</span></td>
</tr>
<tr>
<td class="col-sim">Europäische Union und politische Beteiligung <br><span class="note"><code>eu-politische-beteiligung</code></span></td>
<td class="cell ">8<span class="new">+5</span></td>
<td class="cell ">0<span class="new">+3</span></td>
<td class="cell ">0<span class="new">+5</span></td>
<td class="cell zero">0</td>
<td class="num">8</td>
<td class="num"><span class="delta">+13</span></td>
</tr>
<tr>
<td class="col-sim">Landwirtschaft und globale Klimazonen <br><span class="note"><code>landwirtschaft-klimazonen</code></span></td>
<td class="cell ">8<span class="new">+3</span></td>
<td class="cell ">0<span class="new">+3</span></td>
<td class="cell ">0<span class="new">+7</span></td>
<td class="cell zero">0</td>
<td class="num">8</td>
<td class="num"><span class="delta">+13</span></td>
</tr>
<tr>
<td class="col-sim">Welternaehrung, Konsum und globale Disparitaeten (NEU) <span class="badge b-new">NEU</span><br><span class="note"><code>welternaehrung-konsum-disparitaeten</code></span></td>
<td class="cell ">0<span class="new">+6</span></td>
<td class="cell ">0<span class="new">+6</span></td>
<td class="cell ">0<span class="new">+3</span></td>
<td class="cell zero">0</td>
<td class="num">0</td>
<td class="num"><span class="delta">+15</span></td>
</tr>
</tbody>
</table>
<h2>Pro Sim — Abdeckung mit Ampel-System</h2>
<p class="sub">Pro Sim und Land ein Beispiel-Anker (AT/CH/DE) — plus Ampel für die Gesamtzahl der Anker pro Land. <b>🟢 grün</b> ≥ 6 Anker (gut abgedeckt) · <b>🟡 gelb</b> 3-5 (ok) · <b>🟠 orange</b> 1-2 (dünn) · <b>🔴 rot</b> 0 (gar nicht).</p>
<div class="sim-grid">
<div class="sim-card">
<h4>Busfahrt</h4>
<div class="counts">bestand insgesamt: <b>16</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+46</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 33 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+17 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Welternährung, Landwirtschaft und Klimawandel <div class="note" style="margin-top:2px">GW Kompetenzbereich 1.3 (BGBl. II 1/2023, S. 103)</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>CH — 11 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+11 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Bevölkerung und Migration <div class="note" style="margin-top:2px">LP21 RZG.2.1</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 18 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+18 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> F3 Humangeographische Systeme — Welthandel, Megastädte, Globalisierung <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, F3, S. 14</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>Energiemanager</h4>
<div class="counts">bestand insgesamt: <b>33</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+13</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 27 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+5 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Erneuerbare vs. nicht erneuerbare Energieträger, Klimawandel, Ressourcenverteilung <div class="note" style="margin-top:2px">GW Kompetenzbereich 2.1 (BGBl. II 1/2023, S. 103-104)</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>CH — 10 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+6 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Rohstoffe und Energieträger — Vergleich erneuerbar/nicht erneuerbar <div class="note" style="margin-top:2px">LP21 RZG.1.4</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 7 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+2 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Welthandel, Entwicklung, Klimaprognosen <div class="note" style="margin-top:2px">NI KC Erdkunde Gym Sek I, Beurteilung J10, S. 17-18</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>EU-Werkstatt</h4>
<div class="counts">bestand insgesamt: <b>14</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+19</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 20 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+6 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Import/Export — Außenwirtschaft Österreichs mit EU und Welt <div class="note" style="margin-top:2px">GW Kompetenzbereich 3.3 (BGBl. II 1/2023, S. 105)</div>
</div>
</div>
<div style="background:#fff7e0;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#a37e1a">
<span style="font-size:1.1em">🟡</span>
<span>CH — 4 Anker (ok)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+4 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Schweizer Demokratie — Gewaltenteilung, Föderalismus, direkte Demokratie <div class="note" style="margin-top:2px">LP21 RZG.8.1</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 9 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+9 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> F3 Humangeographische Systeme — Welthandel, Megastädte, Globalisierung <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, F3, S. 14</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>Farmer</h4>
<div class="counts">bestand insgesamt: <b>43</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+48</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 49 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+17 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Bedarfsgerechte Ernährung, Lebensmittelqualität, ressourcenschonende Zubereitung <div class="note" style="margin-top:2px">EH Kompetenzbereich 1 (BGBl. II 1/2023, S. 132)</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>CH — 19 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+15 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Wetter, Klima, Klimazonen, Klimawandel <div class="note" style="margin-top:2px">LP21 RZG.1.2</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 21 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+16 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> F4 Mensch-Umwelt-Beziehungen — Klimawandel, Wassermangel, Bodenversalzung <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, F4, S. 14-15</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>Fluss</h4>
<div class="counts">bestand insgesamt: <b>39</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+19</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 24 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+6 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Plattentektonik und Lebensräume <div class="note" style="margin-top:2px">BU Anwendungsbereiche 3. Kl. (BGBl. II 1/2023, S. 91)</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>CH — 14 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+6 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Naturphänomene und Naturereignisse — Plattentektonik, Erosion, Vulkanismus <div class="note" style="margin-top:2px">LP21 RZG.1.3</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 16 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+7 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> F2 Naturgeographische Systeme — Wasserkreislauf, Klima, Ökosysteme <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, F2, S. 13-14</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>Heli</h4>
<div class="counts">bestand insgesamt: <b>50</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+20</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 34 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+4 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Naturgefahren, Wechselwirkung Natur/Wirtschaft, solidarisches Handeln <div class="note" style="margin-top:2px">GW Kompetenzbereich 1.4 (BGBl. II 1/2023, S. 103)</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>CH — 14 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+6 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Tourismus — Alpenraum, Mittelmeerraum, nachhaltiger Tourismus <div class="note" style="margin-top:2px">LP21 RZG.2.5</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 19 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+10 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> O3 Kartenkompetenz — physische, thematische Karten, GIS <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, O3, S. 17-18</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>Klima</h4>
<div class="counts">bestand insgesamt: <b>22</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+40</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 25 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+14 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Ernährung individuell/sozial/global; Nachhaltigkeit Ökologie/Ökonomie/Soziales <div class="note" style="margin-top:2px">EH Zentrale Konzepte (BGBl. II 1/2023, S. 131-132)</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>CH — 12 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+8 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Wetter, Klima, Klimazonen, Klimawandel <div class="note" style="margin-top:2px">LP21 RZG.1.2</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 23 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+18 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> F2 Naturgeographische Systeme — Wasserkreislauf, Klima, Ökosysteme <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, F2, S. 13-14</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>Klima 3D</h4>
<div class="counts">bestand insgesamt: <b>22</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+18</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 21 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+10 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Landwirtschaft, Biodiversität, anthropogene Einflüsse, CO2 und Klimawandel <div class="note" style="margin-top:2px">BU Anwendungsbereiche 4. Kl. (BGBl. II 1/2023, S. 91-92)</div>
</div>
</div>
<div style="background:#fff7e0;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#a37e1a">
<span style="font-size:1.1em">🟡</span>
<span>CH — 5 Anker (ok)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+1 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Wetter, Klima, Klimazonen, Klimawandel <div class="note" style="margin-top:2px">LP21 RZG.1.2</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 12 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+7 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> F2 Naturgeographische Systeme — Wasserkreislauf, Klima, Ökosysteme <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, F2, S. 13-14</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>Logistik</h4>
<div class="counts">bestand insgesamt: <b>26</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+41</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 41 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+15 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Regional, saisonal, globale Produktionsketten, Nachhaltigkeit <div class="note" style="margin-top:2px">EH Anwendungsbereiche Kb 2 (BGBl. II 1/2023, S. 132-133)</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>CH — 12 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+12 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Mobilität und Transport — nachhaltiges Mobilitätsverhalten <div class="note" style="margin-top:2px">LP21 RZG.2.4</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 14 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+14 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> F3 Humangeographische Systeme — Welthandel, Megastädte, Globalisierung <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, F3, S. 14</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>Sonnensystem</h4>
<div class="counts">bestand insgesamt: <b>52</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+11</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 34 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+2 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Plattentektonik und Lebensräume <div class="note" style="margin-top:2px">BU Anwendungsbereiche 3. Kl. (BGBl. II 1/2023, S. 91)</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>CH — 10 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+2 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Erde als Planet — Gestalt, Rotation, Revolution <div class="note" style="margin-top:2px">LP21 RZG.1.1</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 16 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+7 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> F1 Erde als Planet — Größe, Gestalt, Aufbau, Achsneigung, Gravitation <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, F1, S. 12-13</div>
</div>
</div>
</div>
<div class="sim-card">
<h4>Weltkueche</h4>
<div class="counts">bestand insgesamt: <b>0</b> Anker · neu aus Phase 3: <b style="color:#4a7c4e">+47</b></div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>AT — 20 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+20 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Bedarfsgerechte Ernährung, Lebensmittelqualität, ressourcenschonende Zubereitung <div class="note" style="margin-top:2px">EH Kompetenzbereich 1 (BGBl. II 1/2023, S. 132)</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>CH — 12 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+12 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> Lebensweisen und Ungleichheiten — Armut, Hunger, Bildung <div class="note" style="margin-top:2px">LP21 RZG.2.2</div>
</div>
</div>
<div style="background:#e3e9d6;border-radius:6px;padding:8px 10px;margin-top:6px">
<div style="display:flex;align-items:center;gap:8px;font-size:.78rem;font-weight:700;color:#4a7c4e">
<span style="font-size:1.1em">🟢</span>
<span>DE — 15 Anker (gut)</span>
<span style="margin-left:auto;color:#4a7c4e;font-weight:700">+15 neu</span> </div>
<div style="font-size:.8rem;color:#444;margin-top:4px;line-height:1.4">
<b>Beispiel:</b> F3 Humangeographische Systeme — Welthandel, Megastädte, Globalisierung <div class="note" style="margin-top:2px">DGfG Bildungsstandards 2020, F3, S. 14</div>
</div>
</div>
</div>
</div>
<h2>Themen-Luecken und Sim-Abdeckung</h2>
<p class="sub">Lehrplan-Begriffe, die in Phase 1 oder 2 als "nicht woertlich abgedeckt" gemeldet wurden — mit Sim-Querverweis.</p>
<div class="gap-list">
<div class="gap-item">
<h4>Plantage / Monokultur (Begriff)</h4>
<div class="gap-line"><b>Sim-Abdeckung:</b> JA: Farmer-Sim modelliert Cluster-Risiko bei Monokultur; weltkueche zeigt Plantage-Klimabilanz.</div>
<div class="gap-line"><b>Lehrplan-Verankerung:</b> AT: nicht woertlich. BU 4. Kl. AT spricht von &quot;Charakteristika der konventionellen Landwirtschaft&quot;. DE: NRW IF6 + BY-Gym-Geo10-LB7 nennen &quot;Plantagenwirtschaft&quot; woertlich. CH: WAH/RZG.3.2 nennt &quot;Plantage&quot; als Produktionsform.</div>
<div class="status partial">teilweise abgedeckt — AT-Lehrplan-Luecke. DE+CH wortwoertlich.</div>
</div>
<div class="gap-item">
<h4>Fair Trade / fairer Handel (Begriff)</h4>
<div class="gap-line"><b>Sim-Abdeckung:</b> NEIN — kein Sim-Konzept dafuer. Sinngemaess: weltkueche Klimabilanz + Farmer Importpreise.</div>
<div class="gap-line"><b>Lehrplan-Verankerung:</b> Begriff in keinem der Lehrplaene woertlich (AT/CH/DE). Sinngemaess ueber Globalisierungsbereiche.</div>
<div class="status ">Sim-Luecke — Vorschlag: Fair-Trade-Badges in weltkueche-Rezepten.</div>
</div>
<div class="gap-item">
<h4>Klimazonen explizit (Koeppen-Geiger)</h4>
<div class="gap-line"><b>Sim-Abdeckung:</b> JA: Farmer (Sahel-Cluster, Tropen), klima (Klimazonen-Karte), klima-3d.</div>
<div class="gap-line"><b>Lehrplan-Verankerung:</b> AT: Begriff &quot;Klimazonen&quot; nicht woertlich im GW Sek I. DE: NRW IF5 &quot;Klimazonen der Erde&quot; + BY-Rs-Geo7 &quot;Klima-/Vegetationszonen&quot;. CH: RZG.1.2 &quot;Landschaftszonen&quot; + &quot;Kalte/gemaessigte/Subtropen-/Tropenzone&quot;.</div>
<div class="status ">AT-Luecke. DE+CH stark verankert. Sim deckt es ab.</div>
</div>
<div class="gap-item">
<h4>EU-Institutionen (Kommission, Parlament, Ministerrat) namentlich</h4>
<div class="gap-line"><b>Sim-Abdeckung:</b> JA: EU-Werkstatt thematisiert Buergerinitiative — Institutionsnamen jedoch implizit.</div>
<div class="gap-line"><b>Lehrplan-Verankerung:</b> AT: GW 4.2 nennt nur &quot;vier Grundfreiheiten, Euro, Bildungskooperationen&quot;. GPB 4. Kl. spricht von EU als Wirtschafts-/Friedensprojekt. Keine Institutionsnamen woertlich. DE: NRW IF7 + BY-Gym-Geo10 thematisieren EU-Politik. CH: RZG.8.3 spricht nur abstrakt von &quot;europaeischer Einigung&quot; + Schweiz-Position.</div>
<div class="status ">Plattform-weite Luecke — kein Lehrplan nennt Kommission/Parlament/Rat woertlich. Atlas-Empfehlung: EU-Werkstatt kann Institutionsnamen einfuehren als Plus.</div>
</div>
<div class="gap-item">
<h4>Systemisches Denken explizit</h4>
<div class="gap-line"><b>Sim-Abdeckung:</b> JA: Plattform-Kompetenz #46 systemisches-denken existiert; logistik + klima nutzen sie.</div>
<div class="gap-line"><b>Lehrplan-Verankerung:</b> AT: GW 4.3 &quot;Wandel der Machtverhaeltnisse zwischen Staaten ... NGOs, Konzernen&quot;. DE: DGfG-F2 &quot;Zusammenwirken von Geofaktoren ... als System darstellen&quot;; NRW SK1 &quot;Geofaktoren-Zusammenwirken&quot;. CH: keine eigene Kompetenz, implizit in RZG.3.x.</div>
<div class="status ">DE explizit, AT sinngemaess, CH implizit.</div>
</div>
<div class="gap-item">
<h4>Logistik / Disposition als LP-Anker</h4>
<div class="gap-line"><b>Sim-Abdeckung:</b> JA: logistik-Sim Kern.</div>
<div class="gap-line"><b>Lehrplan-Verankerung:</b> AT: GW 2.2 + GW 3.3 (Import/Export). DE: NRW IF10 &quot;Just-in-time-Produktion&quot; + DGfG-F3 &quot;Welthandel&quot;. CH: WAH.2.2 &quot;globale Warenstroeme, Import/Export, Logistik&quot; woertlich.</div>
<div class="status ">Stark verankert. Plattform-Kompetenz #43 wirtschaft-logistikverstaendnis matcht direkt.</div>
</div>
<div class="gap-item">
<h4>Welternaehrung &amp; Disparitaeten</h4>
<div class="gap-line"><b>Sim-Abdeckung:</b> JA: Weltkueche + Farmer.</div>
<div class="gap-line"><b>Lehrplan-Verankerung:</b> AT: EH 2. Kl. + UT 13 + GW 1.3. DE: NRW IF7 + BY-Gym-Geo10-LB2 + BY-Rs-Geo9. CH: WAH.4.5 + NMG.7.4 + RZG.2.2.</div>
<div class="status ">In ALLEN drei Laendern explizit. Loest neue Plattform-Kompetenz #108 welternaehrung-konsum-disparitaeten aus.</div>
</div>
<div class="gap-item">
<h4>Plantage / Monokultur als Sim-Mechanik</h4>
<div class="gap-line"><b>Sim-Abdeckung:</b> JA: Farmer-Cluster-Risiko, Schaedlingsanfaelligkeit. Welternaehrung-Sim Rezepte.</div>
<div class="gap-line"><b>Lehrplan-Verankerung:</b> Siehe oben.</div>
<div class="status full">Sim deckt es voll ab.</div>
</div>
</div>
<h2>Methodik und Quellen</h2>
<details>
<summary>Datenquellen, Validierungsstatus, Fall-Back-Hinweise</summary>
<div>
<h3>AT — BGBl. II 1/2023</h3>
<p>RIS Rechtsinformationssystem des Bundes. Direkter PDF-Download + pdftotext-Extraktion. Wortwoertliche Zitate. 31 neue Anker.</p>
<p class="note">Quick-Fixes: 9 Subject-Korrekturen (5x "Politische Bildung" -> "Geschichte und Politische Bildung — Querschnitt", 4x "Informatische Bildung" -> "Digitale Grundbildung"). Optional: 33 GW-Anker mit Subject "GW" -> "Geografie und wirtschaftliche Bildung".</p>
<h3>CH — Lehrplan 21 / Kanton St. Gallen</h3>
<p>Quelle: <code>sg.lehrplan.ch</code> (Live-Auftritt Kanton St. Gallen, bestaetigt 2026-06-08 via WebSearch). LP21-Texte national einheitlich.</p>
<p class="note">URL-Verifikation: WebFetch HTTP 403 (Bot-Block) — wie bei v-fe.lehrplan.ch und gr.lehrplan.ch. URL-Schema (Codes b|id|4 fuer Fachbereiche) identisch. Bei manueller Pruefung von Thomas: 1:1-Match zur Stamm-LP21-Struktur erwartet. 41 neue Anker.</p>
<h3>DE — DGfG / NRW / NI / BY</h3>
<p>4 Quellen:</p>
<ul style="padding-left:18px">
<li><b>DGfG Bildungsstandards 2020</b> (10. Aufl., VGDH-PDF): 11 Anker (10 verwertet, DGfG-M2 als Querschnitt weggelassen)</li>
<li><b>NRW Kernlehrplan G9 Erdkunde 2019</b>: 14 Anker</li>
<li><b>Niedersachsen Kerncurriculum Gymnasium Erdkunde</b>: 7 Anker</li>
<li><b>Bayern LehrplanPLUS (Gym 5/7/10 + RS 7/8/9)</b>: 15 Anker</li>
</ul>
<p class="note">Quick-Fix: 4 Anker mit DGfG-Tot-URL <code>geographie.de/publikationen/</code> auf <code>vgdh.de/wp-content/uploads/2023/08/Bildungsstandards_Geographie_2020_Web.pdf</code> aktualisiert.</p>
<h3>Neue Plattform-Kompetenz</h3>
<p><code>welternaehrung-konsum-disparitaeten</code> — konsolidiert die AT-Vorschlagskompetenz "ernaehrungs-und-konsumkompetenz" und die DE-Vorschlagskompetenz "welternaehrung-disparitaeten" zu einer Plattform-Kompetenz mit wortwoertlichen Belegen aus EH 2. Kl. AT, UT 13 AT, NRW IF7, BY-Gym-Geo10-LB2, BY-Rs-Geo9, WAH.2.2 CH, WAH.4.5 CH, NMG.7.4 CH.</p>
</div>
</details>
</body>
</html>
@@ -1,776 +0,0 @@
[
{
"id": 1082,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1083,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1084,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1085,
"status": "needs_human_review",
"details": "reference_url ist Portal-\/Uebersichtsseite (bildungsserver.berlin-brandenburg.de\/unterricht\/rahmenlehrplaene), nicht der RLP-Teil C Geografie direkt. Der RLP 1-10 Berlin\/Brandenburg ist gueltig (2017+), aber URL ist zu unspezifisch.",
"fix_suggestion": "Auf Direkt-PDF zu \"Teil C Geografie\" des Rahmenlehrplans 1-10 Berlin-Brandenburg verlinken (z. B. bildungsserver.berlin-brandenburg.de\/...\/rlp-1-10-online)."
},
{
"id": 1086,
"status": "ok",
"details": "reference_url ist live (Portal-\/Plan-Seite). Subject \"Geographie\" entspricht offizieller Bezeichnung des verlinkten Bundesland-Lehrplans (HE\/NRW: Erdkunde; BW\/BY\/HH\/SN: Geographie; RP: Erdkunde im Verbund Gesellschaftswissenschaften)."
},
{
"id": 1087,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1088,
"status": "needs_human_review",
"details": "LiLe basiert auf Lehrplan 21 und ist seit 2019 gueltig. Subject RZG passt. URL-Liveness wegen Bot-Block (403) nicht automatisch verifiziert; Domain laut Web-Recherche aktiv. Quote ist redaktionelle Bruecke, nicht woertlich aus LiLe."
},
{
"id": 1089,
"status": "ok",
"details": "reference_url ist live (Portal-\/Plan-Seite). Subject \"Erdkunde\" entspricht offizieller Bezeichnung des verlinkten Bundesland-Lehrplans (HE\/NRW: Erdkunde; BW\/BY\/HH\/SN: Geographie; RP: Erdkunde im Verbund Gesellschaftswissenschaften). Hinweis: Reference-URL ist Uebersichtsseite; das eigentliche KC-PDF (HS\/RS\/Gym) wird von dort verlinkt, aber nicht direkt angesteuert. Praeziserer Direkt-Link zu HE-Erdkunde-KC waere besser."
},
{
"id": 1090,
"status": "needs_human_review",
"details": "reference_url WebFetch HTTP 403 (Bot-Block). Portal cuvo.nibis.de ist Niedersaechsisches Curriculum-Portal, gemaess Web-Recherche aktiv. URL-Liveness manuell verifizieren; Quote manuell pruefen."
},
{
"id": 1091,
"status": "url_dead",
"details": "reference_url liefert HTTP 404 (verifiziert 2026-06-08 via WebFetch).",
"fix_suggestion": "reference_url ersetzen durch https:\/\/vgdh.de\/wp-content\/uploads\/2023\/08\/Bildungsstandards_Geographie_2020_Web.pdf (DGfG 2020, 10. Auflage, durch WebSearch bestaetigt)"
},
{
"id": 1092,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1093,
"status": "subject_wrong",
"details": "Im AT-Lehrplan 2023 (BGBl. II 1\/2023) gibt es kein eigenstaendiges Pflichtfach \"Politische Bildung\". Politische Bildung ist (a) Teil des Fachs \"Geschichte und Politische Bildung\" und (b) Querschnittsthema. Reference-URL ist korrekt (RIS), aber Subject suggeriert ein nicht existierendes Fach.",
"fix_suggestion": "Subject auf \"Geschichte und Politische Bildung\" aendern ODER Quelle als Querschnittsthema kennzeichnen (z. B. \"Querschnitt: Politische Bildung\")."
},
{
"id": 1094,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1095,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1096,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1097,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1098,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1099,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1100,
"status": "needs_human_review",
"details": "BNE ist im Lehrplan 21 als Leitidee\/Querschnitt verankert, nicht als eigenstaendiger Fachbereich. Der URL-Code \"e|200|1\" verweist auf eine Lehrplan-Vorlagen-Sicht (v-fe = Vorlage Fremdevaluation\/Entwurf). Aktuellster Ankerpunkt zu BNE ware lehrplan.ch\/index.php?nav=overview oder kantonale Spezifizierungen. URL-Liveness wegen Bot-Block 403 nicht automatisch verifizierbar.",
"fix_suggestion": "Pruefen, ob ein expliziter LP21-BNE-Querverweis (z. B. https:\/\/www.lehrplan21.ch\/grundlagen-bne) sinnvoller ist als der v-fe-Code."
},
{
"id": 1101,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1102,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1103,
"status": "needs_human_review",
"details": "BNE im LiLe als Querschnittsperspektive vorhanden, aber URL-Code b|6|4 zeigt RZG (Fachbereich), nicht den BNE-Querverweis. Inhaltliche Bindung Geografie<->BNE ist plausibel, aber Quote\/URL koppeln BNE-Marker an RZG-Seite. Manuell pruefen. URL-Liveness wegen Bot-Block nicht automatisch verifizierbar (fl.lehrplan.ch laut Web-Recherche aktiv)."
},
{
"id": 1104,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1105,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1106,
"status": "ok",
"details": "reference_url ist live (Portal-\/Plan-Seite). Subject \"Geographie\" entspricht offizieller Bezeichnung des verlinkten Bundesland-Lehrplans (HE\/NRW: Erdkunde; BW\/BY\/HH\/SN: Geographie; RP: Erdkunde im Verbund Gesellschaftswissenschaften)."
},
{
"id": 1107,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1108,
"status": "needs_human_review",
"details": "LiLe basiert auf Lehrplan 21 und ist seit 2019 gueltig. Subject RZG passt. URL-Liveness wegen Bot-Block (403) nicht automatisch verifiziert; Domain laut Web-Recherche aktiv. Quote ist redaktionelle Bruecke, nicht woertlich aus LiLe."
},
{
"id": 1109,
"status": "needs_human_review",
"details": "reference_url liefert PDF (200 OK), Volltext aus Bot-Sicht nicht extrahierbar. Dateiname und Titel suggerieren passendes Bundesland-\/Fach-Dokument, aber Quote muss manuell gegen den PDF-Inhalt verglichen werden."
},
{
"id": 1110,
"status": "ok",
"details": "reference_url ist live (Portal-\/Plan-Seite). Subject \"Geographie\" entspricht offizieller Bezeichnung des verlinkten Bundesland-Lehrplans (HE\/NRW: Erdkunde; BW\/BY\/HH\/SN: Geographie; RP: Erdkunde im Verbund Gesellschaftswissenschaften). Hinweis: SN-Lehrplan ist 2004 erstmals erlassen, mit Ueberarbeitungen 2009\/2011\/2019. Offiziell weiter gueltig laut Schulportal Sachsen - kein \"version_outdated\", aber inhaltlich der aelteste aktive Plan im Set."
},
{
"id": 1111,
"status": "ok",
"details": "reference_url ist live (Portal-\/Plan-Seite). Subject \"Erdkunde\" entspricht offizieller Bezeichnung des verlinkten Bundesland-Lehrplans (HE\/NRW: Erdkunde; BW\/BY\/HH\/SN: Geographie; RP: Erdkunde im Verbund Gesellschaftswissenschaften). Hinweis: Reference-URL ist Uebersichtsseite; das eigentliche KC-PDF (HS\/RS\/Gym) wird von dort verlinkt, aber nicht direkt angesteuert. Praeziserer Direkt-Link zu HE-Erdkunde-KC waere besser."
},
{
"id": 1112,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1113,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1114,
"status": "subject_wrong",
"details": "Im AT-Lehrplan 2023 (BGBl. II 1\/2023) gibt es kein eigenstaendiges Pflichtfach \"Politische Bildung\". Politische Bildung ist (a) Teil des Fachs \"Geschichte und Politische Bildung\" und (b) Querschnittsthema. Reference-URL ist korrekt (RIS), aber Subject suggeriert ein nicht existierendes Fach.",
"fix_suggestion": "Subject auf \"Geschichte und Politische Bildung\" aendern ODER Quelle als Querschnittsthema kennzeichnen (z. B. \"Querschnitt: Politische Bildung\")."
},
{
"id": 1115,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1116,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1117,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1118,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1119,
"status": "needs_human_review",
"details": "BNE ist im Lehrplan 21 als Leitidee\/Querschnitt verankert, nicht als eigenstaendiger Fachbereich. Der URL-Code \"e|200|1\" verweist auf eine Lehrplan-Vorlagen-Sicht (v-fe = Vorlage Fremdevaluation\/Entwurf). Aktuellster Ankerpunkt zu BNE ware lehrplan.ch\/index.php?nav=overview oder kantonale Spezifizierungen. URL-Liveness wegen Bot-Block 403 nicht automatisch verifizierbar.",
"fix_suggestion": "Pruefen, ob ein expliziter LP21-BNE-Querverweis (z. B. https:\/\/www.lehrplan21.ch\/grundlagen-bne) sinnvoller ist als der v-fe-Code."
},
{
"id": 1120,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1121,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1122,
"status": "needs_human_review",
"details": "BNE im LiLe als Querschnittsperspektive vorhanden, aber URL-Code b|6|4 zeigt RZG (Fachbereich), nicht den BNE-Querverweis. Inhaltliche Bindung Geografie<->BNE ist plausibel, aber Quote\/URL koppeln BNE-Marker an RZG-Seite. Manuell pruefen. URL-Liveness wegen Bot-Block nicht automatisch verifizierbar (fl.lehrplan.ch laut Web-Recherche aktiv)."
},
{
"id": 1123,
"status": "url_dead",
"details": "reference_url liefert HTTP 404 (verifiziert 2026-06-08 via WebFetch).",
"fix_suggestion": "reference_url ersetzen durch https:\/\/vgdh.de\/wp-content\/uploads\/2023\/08\/Bildungsstandards_Geographie_2020_Web.pdf (DGfG 2020, 10. Auflage, durch WebSearch bestaetigt)"
},
{
"id": 1124,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1125,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1126,
"status": "ok",
"details": "reference_url ist live (Portal-\/Plan-Seite). Subject \"Erdkunde\" entspricht offizieller Bezeichnung des verlinkten Bundesland-Lehrplans (HE\/NRW: Erdkunde; BW\/BY\/HH\/SN: Geographie; RP: Erdkunde im Verbund Gesellschaftswissenschaften)."
},
{
"id": 1127,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1128,
"status": "needs_human_review",
"details": "LiLe basiert auf Lehrplan 21 und ist seit 2019 gueltig. Subject RZG passt. URL-Liveness wegen Bot-Block (403) nicht automatisch verifiziert; Domain laut Web-Recherche aktiv. Quote ist redaktionelle Bruecke, nicht woertlich aus LiLe."
},
{
"id": 1129,
"status": "needs_human_review",
"details": "reference_url WebFetch HTTP 403 (Bot-Block). Portal cuvo.nibis.de ist Niedersaechsisches Curriculum-Portal, gemaess Web-Recherche aktiv. URL-Liveness manuell verifizieren; Quote manuell pruefen."
},
{
"id": 1130,
"status": "needs_human_review",
"details": "reference_url liefert PDF (200 OK), Volltext aus Bot-Sicht nicht extrahierbar. Dateiname und Titel suggerieren passendes Bundesland-\/Fach-Dokument, aber Quote muss manuell gegen den PDF-Inhalt verglichen werden."
},
{
"id": 1131,
"status": "subject_wrong",
"details": "Im AT-Lehrplan 2023 ist \"Informatische Bildung\" Querschnittsthema; das eigenstaendige Pflichtfach heisst \"Digitale Grundbildung\". Wenn der Anker ein Fach meinen soll, ist die Bezeichnung falsch.",
"fix_suggestion": "Subject auf \"Digitale Grundbildung\" aendern (wenn Fach gemeint) ODER explizit als \"Querschnitt: Informatische Bildung\" auszeichnen."
},
{
"id": 1132,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1133,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1134,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1135,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1136,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1137,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1138,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1139,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1140,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1141,
"status": "url_dead",
"details": "reference_url liefert HTTP 404 (verifiziert 2026-06-08 via WebFetch).",
"fix_suggestion": "reference_url ersetzen durch https:\/\/vgdh.de\/wp-content\/uploads\/2023\/08\/Bildungsstandards_Geographie_2020_Web.pdf (DGfG 2020, 10. Auflage, durch WebSearch bestaetigt)"
},
{
"id": 1142,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1143,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1144,
"status": "ok",
"details": "reference_url ist live (Portal-\/Plan-Seite). Subject \"Geographie\" entspricht offizieller Bezeichnung des verlinkten Bundesland-Lehrplans (HE\/NRW: Erdkunde; BW\/BY\/HH\/SN: Geographie; RP: Erdkunde im Verbund Gesellschaftswissenschaften)."
},
{
"id": 1145,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1146,
"status": "needs_human_review",
"details": "LiLe basiert auf Lehrplan 21 und ist seit 2019 gueltig. Subject RZG passt. URL-Liveness wegen Bot-Block (403) nicht automatisch verifiziert; Domain laut Web-Recherche aktiv. Quote ist redaktionelle Bruecke, nicht woertlich aus LiLe."
},
{
"id": 1147,
"status": "ok",
"details": "reference_url ist live (Portal-\/Plan-Seite). Subject \"Erdkunde\" entspricht offizieller Bezeichnung des verlinkten Bundesland-Lehrplans (HE\/NRW: Erdkunde; BW\/BY\/HH\/SN: Geographie; RP: Erdkunde im Verbund Gesellschaftswissenschaften). Hinweis: Reference-URL ist Uebersichtsseite; das eigentliche KC-PDF (HS\/RS\/Gym) wird von dort verlinkt, aber nicht direkt angesteuert. Praeziserer Direkt-Link zu HE-Erdkunde-KC waere besser."
},
{
"id": 1148,
"status": "needs_human_review",
"details": "reference_url liefert PDF (200 OK), Volltext aus Bot-Sicht nicht extrahierbar. Dateiname und Titel suggerieren passendes Bundesland-\/Fach-Dokument, aber Quote muss manuell gegen den PDF-Inhalt verglichen werden."
},
{
"id": 1149,
"status": "subject_wrong",
"details": "Im AT-Lehrplan 2023 (BGBl. II 1\/2023) gibt es kein eigenstaendiges Pflichtfach \"Politische Bildung\". Politische Bildung ist (a) Teil des Fachs \"Geschichte und Politische Bildung\" und (b) Querschnittsthema. Reference-URL ist korrekt (RIS), aber Subject suggeriert ein nicht existierendes Fach.",
"fix_suggestion": "Subject auf \"Geschichte und Politische Bildung\" aendern ODER Quelle als Querschnittsthema kennzeichnen (z. B. \"Querschnitt: Politische Bildung\")."
},
{
"id": 1150,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1151,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1152,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1153,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1154,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1155,
"status": "needs_human_review",
"details": "BNE ist im Lehrplan 21 als Leitidee\/Querschnitt verankert, nicht als eigenstaendiger Fachbereich. Der URL-Code \"e|200|1\" verweist auf eine Lehrplan-Vorlagen-Sicht (v-fe = Vorlage Fremdevaluation\/Entwurf). Aktuellster Ankerpunkt zu BNE ware lehrplan.ch\/index.php?nav=overview oder kantonale Spezifizierungen. URL-Liveness wegen Bot-Block 403 nicht automatisch verifizierbar.",
"fix_suggestion": "Pruefen, ob ein expliziter LP21-BNE-Querverweis (z. B. https:\/\/www.lehrplan21.ch\/grundlagen-bne) sinnvoller ist als der v-fe-Code."
},
{
"id": 1156,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1157,
"status": "needs_human_review",
"details": "Subject ist Lehrplan-21-Fachbereich, plausibel. URL-Liveness fuer v-fe.lehrplan.ch nicht automatisch verifizierbar (WebFetch 403, Bot-Block). Domain laut Web-Recherche aktiv, Code-Schema (b|<id>|4) ist Lehrplan-21-konform. Quote ist redaktionelle Bruecke (kein woertliches LP21-Zitat) und muss manuell gegen den offiziellen LP21-Wortlaut geprueft werden."
},
{
"id": 1158,
"status": "needs_human_review",
"details": "BNE im LiLe als Querschnittsperspektive vorhanden, aber URL-Code b|6|4 zeigt RZG (Fachbereich), nicht den BNE-Querverweis. Inhaltliche Bindung Geografie<->BNE ist plausibel, aber Quote\/URL koppeln BNE-Marker an RZG-Seite. Manuell pruefen. URL-Liveness wegen Bot-Block nicht automatisch verifizierbar (fl.lehrplan.ch laut Web-Recherche aktiv)."
},
{
"id": 1159,
"status": "url_dead",
"details": "reference_url liefert HTTP 404 (verifiziert 2026-06-08 via WebFetch).",
"fix_suggestion": "reference_url ersetzen durch https:\/\/vgdh.de\/wp-content\/uploads\/2023\/08\/Bildungsstandards_Geographie_2020_Web.pdf (DGfG 2020, 10. Auflage, durch WebSearch bestaetigt)"
},
{
"id": 1160,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1161,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1162,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1163,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1164,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1165,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1166,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1167,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1168,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1169,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1170,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1171,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1172,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1173,
"status": "subject_wrong",
"details": "Im AT-Lehrplan 2023 (BGBl. II 1\/2023) gibt es kein eigenstaendiges Pflichtfach \"Politische Bildung\". Politische Bildung ist (a) Teil des Fachs \"Geschichte und Politische Bildung\" und (b) Querschnittsthema. Reference-URL ist korrekt (RIS), aber Subject suggeriert ein nicht existierendes Fach.",
"fix_suggestion": "Subject auf \"Geschichte und Politische Bildung\" aendern ODER Quelle als Querschnittsthema kennzeichnen (z. B. \"Querschnitt: Politische Bildung\")."
},
{
"id": 1174,
"status": "subject_wrong",
"details": "Im AT-Lehrplan 2023 ist \"Informatische Bildung\" Querschnittsthema; das eigenstaendige Pflichtfach heisst \"Digitale Grundbildung\". Wenn der Anker ein Fach meinen soll, ist die Bezeichnung falsch.",
"fix_suggestion": "Subject auf \"Digitale Grundbildung\" aendern (wenn Fach gemeint) ODER explizit als \"Querschnitt: Informatische Bildung\" auszeichnen."
},
{
"id": 1175,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1176,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1177,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1178,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1179,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1180,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1181,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1182,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1183,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1184,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1185,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1186,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1187,
"status": "subject_wrong",
"details": "Im AT-Lehrplan 2023 ist \"Informatische Bildung\" Querschnittsthema; das eigenstaendige Pflichtfach heisst \"Digitale Grundbildung\". Wenn der Anker ein Fach meinen soll, ist die Bezeichnung falsch.",
"fix_suggestion": "Subject auf \"Digitale Grundbildung\" aendern (wenn Fach gemeint) ODER explizit als \"Querschnitt: Informatische Bildung\" auszeichnen."
},
{
"id": 1188,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1189,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1190,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1191,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1192,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1193,
"status": "subject_wrong",
"details": "Im AT-Lehrplan 2023 ist \"Informatische Bildung\" Querschnittsthema; das eigenstaendige Pflichtfach heisst \"Digitale Grundbildung\". Wenn der Anker ein Fach meinen soll, ist die Bezeichnung falsch.",
"fix_suggestion": "Subject auf \"Digitale Grundbildung\" aendern (wenn Fach gemeint) ODER explizit als \"Querschnitt: Informatische Bildung\" auszeichnen."
},
{
"id": 1194,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1195,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1196,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1197,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1198,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1199,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1200,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1201,
"status": "subject_wrong",
"details": "Im AT-Lehrplan 2023 (BGBl. II 1\/2023) gibt es kein eigenstaendiges Pflichtfach \"Politische Bildung\". Politische Bildung ist (a) Teil des Fachs \"Geschichte und Politische Bildung\" und (b) Querschnittsthema. Reference-URL ist korrekt (RIS), aber Subject suggeriert ein nicht existierendes Fach.",
"fix_suggestion": "Subject auf \"Geschichte und Politische Bildung\" aendern ODER Quelle als Querschnittsthema kennzeichnen (z. B. \"Querschnitt: Politische Bildung\")."
},
{
"id": 1202,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1203,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1204,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1205,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1206,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1207,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1208,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1209,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1210,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1211,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1212,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1213,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1214,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1215,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1216,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1217,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1218,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1219,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1220,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1221,
"status": "needs_human_review",
"details": "Subject \"GW\" ist gaengiges Kuerzel, offizieller Fachname seit BGBl. II 1\/2023 lautet \"Geografie und wirtschaftliche Bildung\". Reference passt zur aktuellen Verordnung (RIS Gesetzesnummer 20007850 in GeltendeFassung).",
"fix_suggestion": "Optional: Subject auf \"Geografie und wirtschaftliche Bildung\" angleichen (offizielle Bezeichnung 2023)."
},
{
"id": 1222,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1223,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1224,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
},
{
"id": 1225,
"status": "needs_human_review",
"details": "Subject und URL OK. Quote ist eine redaktionelle Brueckenformulierung (kein direktes RIS-Zitat). Wortlaut muss gegen den Volltext der jeweiligen Fachlehrplan-Anlage manuell abgeglichen werden."
}
]
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
-152
View File
@@ -1,152 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>Plattform-Standards · Entwurfswerkzeug</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',system-ui,sans-serif;background:#f5f2eb;color:#2a2a2a;line-height:1.5;padding:24px;max-width:1100px;margin:0 auto}
h1{color:#1f4e5a;font-size:1.5rem;margin-bottom:4px}
.sub{font-size:.82rem;color:#8a8a8a;margin-bottom:14px}
h2{color:#1f4e5a;font-size:1.15rem;margin:28px 0 8px;padding-bottom:4px;border-bottom:2px solid #4a7c8a}
h3{color:#4a7c8a;font-size:1rem;margin:18px 0 8px}
h4{color:#3a3a3a;font-size:.92rem;margin:14px 0 6px;font-weight:700}
p{margin:8px 0}
code{background:#f5f2eb;padding:2px 6px;border-radius:3px;font-family:'JetBrains Mono',Consolas,monospace;font-size:.85em}
pre{background:#1f2a30;color:#e8e4d8;padding:14px 18px;border-radius:8px;overflow:auto;font-family:'JetBrains Mono',Consolas,monospace;font-size:.82rem;line-height:1.5;margin:10px 0}
pre code{background:transparent;color:inherit;padding:0;font-size:inherit}
a{color:#1f4e5a}
.demo{background:#fff;border:1px solid #e0ddd4;border-radius:6px;padding:14px 18px;margin:10px 0}
.demo b{color:#1f4e5a}
.ok-box{background:#dff0e6;border-left:4px solid #5a8a5e;padding:10px 14px;margin:10px 0;border-radius:0 6px 6px 0;font-size:.88rem}
.warn-box{background:#fff7e0;border-left:4px solid #d2a24c;padding:10px 14px;margin:10px 0;border-radius:0 6px 6px 0;font-size:.88rem}
table{width:100%;border-collapse:collapse;font-size:.88rem;background:#fff;border-radius:6px;overflow:hidden;margin:10px 0}
th,td{text-align:left;padding:8px 12px;border-bottom:1px solid #e0ddd4;vertical-align:top}
th{background:#1f4e5a;color:#fff;font-weight:600;font-size:.74rem;text-transform:uppercase;letter-spacing:.04em}
tr:last-child td{border-bottom:none}
/* Demo: real Glossar-Tooltip-Klasse wie in Prod */
.ggs-g{cursor:help;border-bottom:1px dashed currentColor;text-decoration:none;color:inherit;background:rgba(0,0,0,.02);padding:0 2px;border-radius:2px}
.ggs-g:hover{background:rgba(31,75,55,.10);border-bottom-style:solid}
/* einheitliches Entwurfswerkzeug-Menü */
.top-nav{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:10px 14px;margin-bottom:18px;font-size:.86rem;display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.top-nav strong{color:#1f4e5a}
.top-nav a{text-decoration:none;padding:5px 11px;border-radius:6px;color:#1f4e5a}
.top-nav a:hover{background:#f5f2eb}
.top-nav a.active{background:#1f4e5a;color:#fff}
</style>
</head>
<body>
<nav class="top-nav">
<strong>🛠 Entwurfswerkzeug</strong>
<a href="index.html">Übersicht</a>
<a href="../entwurf.html">Entwurf</a>
<a href="../review.html">Review</a>
<a href="accounts.html">🔑 Accounts</a>
<a href="standards.html" class="active">📐 Standards</a>
<a href="legacy/" style="color:#6b6448">📂 legacy/</a>
<a href="toDelete/" style="color:#9c4d2e">📂 toDelete/</a>
<a href="../../App/admin-sitemap.html" target="_blank">📊 Sitemap</a>
</nav>
<h1>📐 Plattform-Standards</h1>
<p class="sub">UI-Patterns, die in allen Sims gleich aussehen + funktionieren sollen. Pflegt Atlas, hier dokumentiert.</p>
<!-- ============================ -->
<h2>🏷️ Glossar-Tooltip-Pattern</h2>
<p>Bei Fachbegriffen in Sim-Texten: kleines Popup mit Kurzerklärung + Link zum vollen Glossar-Eintrag. Erprobt seit Heli + Klima 2D/3D.</p>
<h3>So sieht's aus</h3>
<div class="demo">
Das ist ein Beispieltext mit einem
<span class="ggs-g" data-glossar="welthandel">Welthandel</span>-Begriff drin
und auch <span class="ggs-g" data-glossar="klimazone">Klimazone</span> ist klickbar.
Beim Klick öffnet sich rechts unter dem Begriff ein kleiner Popup mit Definition.
</div>
<h3>Markup-Standard</h3>
<pre><code>&lt;span class="ggs-g" data-glossar="welthandel"&gt;Welthandel&lt;/span&gt;</code></pre>
<p>Regel: <code>data-glossar</code>-Attribut hält den <code>key_slug</code> des Glossar-Eintrags. Die CSS-Klasse <code>ggs-g</code> sorgt für die gestrichelte Unterlinie + Hover-Effekt + ist der Trigger für den JS-Handler.</p>
<h3>Einbindung im Sim-Wrapper (PHP)</h3>
<pre><code>// in App/pages/&lt;sim&gt;.php nach dem Live-Heartbeat-Script:
$glossarScript = '&lt;script src="' . BASE_PATH . '/assets/js/glossar-tooltip.js" defer&gt;&lt;/script&gt;'
. '&lt;script&gt;window.addEventListener("DOMContentLoaded",function(){'
. 'if(window.GlossarTooltip)GlossarTooltip.init({apiBase:' . json_encode(BASE_PATH . '/api') . ',moduleId:"&lt;sim-slug&gt;"});'
. '});&lt;/script&gt;';
$html = str_replace('&lt;/body&gt;', $glossarScript . "\n&lt;/body&gt;", $html);</code></pre>
<h3>API der Lib</h3>
<table>
<thead><tr><th>Funktion</th><th>Zweck</th></tr></thead>
<tbody>
<tr><td><code>GlossarTooltip.init({apiBase, moduleId, fallback})</code></td><td>Aktiviert das Pattern auf der Seite. Lädt die Glossar-Snippets pro Modul via API-Call <code>/api/glossar.php?module=&lt;moduleId&gt;</code>.</td></tr>
<tr><td><code>GlossarTooltip.addFallback(key, {title, text})</code></td><td>Für Begriffe ohne DB-Eintrag (oder bei Offline-Demo): lokales Snippet hinzufügen.</td></tr>
<tr><td><code>GlossarTooltip.markup(label, slug)</code></td><td>Hilfsfunktion für dynamisch generierte HTML-Strings: liefert das fertige <code>&lt;span&gt;</code>-Markup.</td></tr>
</tbody>
</table>
<h3>Wo schon im Einsatz</h3>
<table>
<thead><tr><th>Sim</th><th>Status</th><th>Pattern-Variante</th></tr></thead>
<tbody>
<tr><td>Heli</td><td>✓ aktiv</td><td>eigene <code>heli-glossar-term</code>-Klasse + lokale JS-Implementierung (Vorbild für das Pattern)</td></tr>
<tr><td>Klima 2D/3D</td><td>✓ aktiv</td><td>eigene Klima-Variante</td></tr>
<tr><td>Weltküche</td><td>✓ seit 2026-06-08</td><td><b>Plattform-Standard via <code>/assets/js/glossar-tooltip.js</code></b></td></tr>
<tr><td>Andere Sims</td><td>⏳ ausstehend</td><td>Migration auf Plattform-Lib empfohlen (siehe „Migrations-Plan" unten)</td></tr>
</tbody>
</table>
<div class="ok-box">
<b>Plattform-Lib:</b> <code>App/assets/js/glossar-tooltip.js</code> (Stand 2026-06-08).
Pure Vanilla-JS, kein Framework, mobile-/iPad-tauglich. CSS wird automatisch injiziert.
</div>
<h3>Migrations-Plan für andere Sims</h3>
<ol style="margin:6px 0 10px 24px">
<li>Im jeweiligen Wrapper (<code>App/pages/&lt;sim&gt;.php</code>) das Script einbinden (Snippet oben).</li>
<li>Eigene Glossar-CSS-Klassen (<code>.heli-glossar-term</code>, <code>.klima-glossar-term</code> usw.) durch <code>ggs-g</code> ersetzen.</li>
<li>Eigene JS-Click-Handler entfernen — die Plattform-Lib übernimmt.</li>
<li>Optional: lokale Fallback-Snippets via <code>GlossarTooltip.addFallback()</code> nachreichen.</li>
</ol>
<div class="warn-box">
<b>Wichtig:</b> Beim Migrieren NICHTS löschen, bevor das neue Pattern getestet ist. Erst neuen Code dazu, beide laufen lassen, dann altes raus.
</div>
<!-- ============================ -->
<h2>🎵 Audio-Signal „Atlas fertig"</h2>
<p>Atlas spielt das MP3 <code>App/sims/heli/sounds/dev/atlas-fertig.mp3</code> ab — IMMER wenn der Ball bei Thomas liegt (Aufgabe fertig ODER warten auf Genehmigung). Details: <code>memory/feedback_atlas_fertig_audio.md</code>.</p>
<!-- ============================ -->
<h2>📦 Sim-Wrapper-Standard</h2>
<p>Jede Sim hat einen <code>App/pages/&lt;slug&gt;.php</code>-Wrapper:</p>
<ul style="margin:6px 0 10px 24px">
<li>Lädt Plattform-Session-Kontext (<code>WK_SESSION_ID</code>, <code>WK_STUDENT_NAME</code>, <code>WK_CLASS_ID</code>)</li>
<li>Injiziert <code>BASE_PATH</code> als <code>window.&lt;SIM&gt;_BASE</code> + <code>window.&lt;SIM&gt;_API_BASE</code></li>
<li>Hängt <code>live-client.js</code> + <code>glossar-tooltip.js</code> vor <code>&lt;/body&gt;</code></li>
<li>Setzt <code>Cache-Control: no-store</code> (game.html-Updates wirken sofort)</li>
<li>Biegt Asset-Pfade um: <code>preg_replace</code> auf <code>href="assets/..."</code> und <code>src="assets/..."</code></li>
</ul>
<!-- ============================ -->
<h2>🌍 GGS_LIVE_STATE-Hook</h2>
<p>Jede Sim definiert <code>window.GGS_LIVE_STATE = function(){…}</code> → liefert State-Snapshot für Lehrer-Live-Cockpit. Mindestens:</p>
<pre><code>{
phase: 'browsing' | 'recipe' | 'researching' | …,
score: 0,
completed: 0, // erledigte Aufgaben/Gerichte
completedTotal: 30, // max
badgesEarned: 0,
badgesTotal: 10,
levelWon: false
}</code></pre>
<p>Der Live-Heartbeat schickt das alle 4 s an <code>/api/live.php</code>.</p>
<footer style="margin:32px 0 24px;text-align:center;font-size:.75rem;color:#8a8a8a">
Liegt unter <code>.dontDeploy/entwurfswerkzeug/standards.html</code> · wird nicht deployed.
</footer>
</body>
</html>
@@ -1,297 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Lehrkräfte-Dashboard</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="assets/fonts/inter.css">
<style>
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
:root {
--bg: #f7f6f3; --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;
}
body { font-family:'Inter',system-ui,sans-serif; background:var(--bg); color:var(--text); line-height:1.55; }
.nav { padding:.7rem 2rem; display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid rgba(0,0,0,.04); background:var(--white); }
.nav-brand { display:flex; align-items:center; gap:.5rem; font-weight:800; font-size:1rem; color:var(--fjord); text-decoration:none; }
.nav-brand img { width:28px; height:28px; border-radius:6px; }
.nav-user { display:flex; align-items:center; gap:.6rem; font-size:.85rem; }
.avatar { width:32px; height:32px; border-radius:50%; background:var(--fjord); color:#fff; display:flex; align-items:center; justify-content:center; font-weight:700; font-size:.78rem; }
.layout { display:grid; grid-template-columns:240px 1fr; min-height:calc(100vh - 60px); }
.sidebar { background:var(--white); border-right:1px solid rgba(0,0,0,.05); padding:1.2rem 1rem; }
.sidebar h4 { font-size:.65rem; font-weight:700; color:var(--text3); text-transform:uppercase; letter-spacing:.08em; margin:1rem 0 .4rem; }
.sidebar h4:first-child { margin-top:0; }
.sidebar a { display:block; padding:.4rem .7rem; color:var(--text2); text-decoration:none; border-radius:8px; font-size:.82rem; font-weight:500; margin-bottom:1px; transition:all .2s; }
.sidebar a:hover, .sidebar a.active { background:var(--fjord-l); color:var(--fjord); }
.main { padding:1.5rem 2rem; }
.page-header { display:flex; justify-content:space-between; align-items:center; margin-bottom:1.2rem; }
.page-header h1 { font-size:1.6rem; font-weight:800; letter-spacing:-.02em; }
.page-header p { color:var(--text3); font-size:.85rem; }
.btn { display:inline-flex; align-items:center; gap:.4rem; padding:.5rem 1.1rem; border-radius:10px; font-weight:600; font-size:.82rem; border:none; cursor:pointer; transition:all .2s; text-decoration:none; }
.btn-p { background:var(--fjord); color:#fff; }
.btn-p:hover { background:var(--fjord-d); }
.btn-o { background:var(--white); color:var(--fjord); border:1.5px solid rgba(74,124,138,.3); }
.grid { display:grid; gap:1rem; }
.grid-3 { grid-template-columns:repeat(3,1fr); }
.grid-2 { grid-template-columns:1fr 1fr; }
.grid-4 { grid-template-columns:repeat(4,1fr); }
.card { background:var(--white); border-radius:14px; border:1px solid rgba(0,0,0,.04); padding:1.1rem; box-shadow:0 2px 10px rgba(0,0,0,.03); }
.card h3 { font-size:.78rem; font-weight:700; color:var(--text3); text-transform:uppercase; letter-spacing:.06em; margin-bottom:.6rem; }
.card-big-num { font-size:2rem; font-weight:900; letter-spacing:-.03em; }
.card-trend { font-size:.75rem; color:var(--moss); font-weight:600; margin-top:.2rem; }
/* Class table */
.classes-table { width:100%; border-collapse:collapse; font-size:.85rem; }
.classes-table th, .classes-table td { padding:.6rem .8rem; text-align:left; border-bottom:1px solid rgba(0,0,0,.05); }
.classes-table th { font-size:.7rem; font-weight:700; color:var(--text3); text-transform:uppercase; letter-spacing:.06em; }
.classes-table tr:hover { background:#fafaf8; }
.student-row { display:flex; align-items:center; gap:.5rem; }
.progress-bar { width:80px; height:6px; background:#e8e5dc; border-radius:3px; overflow:hidden; }
.progress-fill { height:100%; border-radius:3px; }
.badge { display:inline-block; padding:2px 9px; border-radius:6px; font-size:.68rem; font-weight:600; }
.b-on { background:var(--moss-l); color:var(--moss); }
.b-off { background:#f0eeea; color:var(--text3); }
.b-progress { background:var(--fjord-l); color:var(--fjord); }
.b-warn { background:var(--sand-l); color:var(--sand); }
/* Sim card with toggle */
.sim-toggle-card { display:flex; align-items:center; gap:.8rem; padding:.8rem; border-radius:10px; background:#fafaf8; border:1px solid rgba(0,0,0,.04); margin-bottom:.5rem; }
.sim-toggle-card-icon { font-size:1.5rem; }
.sim-toggle-card-info { flex:1; }
.sim-toggle-card-info h5 { font-size:.85rem; font-weight:700; }
.sim-toggle-card-info p { font-size:.72rem; color:var(--text3); }
.toggle { width:36px; height:20px; background:#d4d4d0; border-radius:10px; position:relative; cursor:pointer; transition:all .2s; }
.toggle.on { background:var(--moss); }
.toggle::after { content:''; position:absolute; top:2px; left:2px; width:16px; height:16px; background:#fff; border-radius:50%; transition:all .2s; box-shadow:0 1px 3px rgba(0,0,0,.2); }
.toggle.on::after { left:18px; }
.alert { background:var(--coral-l); border-left:3px solid var(--coral); padding:.6rem .8rem; border-radius:8px; font-size:.78rem; margin-bottom:.5rem; }
.alert strong { color:var(--coral); }
.demo-banner { background:var(--sand-l); color:var(--sand); padding:.5rem 1rem; text-align:center; font-size:.78rem; font-weight:600; }
</style>
</head>
<body>
<div class="demo-banner">⚠️ Demo-Mockup — alle Daten sind erfunden, kein Backend angeschlossen</div>
<nav class="nav">
<a href="index.html" class="nav-brand"><img src="assets/img/logo.png" alt="">GeoGraSim · Dashboard</a>
<div class="nav-user">
<span style="color:var(--text2)">Mag. Schroffenegger</span>
<div class="avatar">TS</div>
</div>
</nav>
<div class="layout">
<aside class="sidebar">
<h4>Übersicht</h4>
<a href="#" class="active">📊 Dashboard</a>
<a href="#">👥 Klassen</a>
<a href="#">🎯 Simulationen</a>
<a href="#">📈 Berichte</a>
<h4>Meine Klassen</h4>
<a href="#">1A — 24 Schüler*innen</a>
<a href="#">1B — 22 Schüler*innen</a>
<a href="#">2A — 25 Schüler*innen</a>
<a href="#">3B — 23 Schüler*innen</a>
<h4>Tools</h4>
<a href="#">🗳️ Live-Abstimmung</a>
<a href="#">📥 Export (PDF)</a>
<a href="#">⚙️ Einstellungen</a>
</aside>
<main class="main">
<div class="page-header">
<div>
<h1>Klasse 1A — Übersicht</h1>
<p>24 Schüler*innen · Letzte Aktivität: vor 2 Stunden</p>
</div>
<div style="display:flex;gap:.5rem">
<button class="btn btn-o">📥 Bericht exportieren</button>
<button class="btn btn-p">🚀 Simulation starten</button>
</div>
</div>
<!-- Top stats row -->
<div class="grid grid-4" style="margin-bottom:1rem">
<div class="card">
<h3>Aktive Schüler*innen</h3>
<div class="card-big-num" style="color:var(--fjord)">18 / 24</div>
<div class="card-trend">↗ +3 seit gestern</div>
</div>
<div class="card">
<h3>Abgeschlossene Simulationen</h3>
<div class="card-big-num" style="color:var(--moss)">142</div>
<div class="card-trend">↗ 87% Erfolgsquote</div>
</div>
<div class="card">
<h3>Durchschn. Lernzeit</h3>
<div class="card-big-num" style="color:var(--sand)">23 min</div>
<div class="card-trend" style="color:var(--text3)">pro Simulation</div>
</div>
<div class="card">
<h3>Identifizierte Fehlkonzepte</h3>
<div class="card-big-num" style="color:var(--coral)">5</div>
<div class="card-trend" style="color:var(--coral)">⚠ Aufmerksamkeit nötig</div>
</div>
</div>
<!-- Two column section -->
<div class="grid grid-2" style="margin-bottom:1rem">
<!-- Active simulation -->
<div class="card">
<h3>🔴 Live: Treibhauseffekt-Simulator</h3>
<p style="font-size:.85rem;margin:.5rem 0 .8rem;color:var(--text2)">12 von 24 Schüler*innen bearbeiten gerade die Simulation.</p>
<table class="classes-table">
<thead>
<tr><th>Schüler*in</th><th>Phase</th><th>Fortschritt</th><th>Zeit</th></tr>
</thead>
<tbody>
<tr>
<td><div class="student-row">👤 Anna B.</div></td>
<td><span class="badge b-progress">Observe</span></td>
<td><div class="progress-bar"><div class="progress-fill" style="width:75%;background:var(--fjord)"></div></div></td>
<td>14:32</td>
</tr>
<tr>
<td><div class="student-row">👤 Lukas F.</div></td>
<td><span class="badge b-on">Reflect</span></td>
<td><div class="progress-bar"><div class="progress-fill" style="width:90%;background:var(--moss)"></div></div></td>
<td>18:45</td>
</tr>
<tr>
<td><div class="student-row">👤 Sara M.</div></td>
<td><span class="badge b-progress">Predict</span></td>
<td><div class="progress-bar"><div class="progress-fill" style="width:30%;background:var(--fjord)"></div></div></td>
<td>05:12</td>
</tr>
<tr>
<td><div class="student-row">👤 Tim H.</div></td>
<td><span class="badge b-warn">Pausiert</span></td>
<td><div class="progress-bar"><div class="progress-fill" style="width:55%;background:var(--sand)"></div></div></td>
<td>09:20</td>
</tr>
<tr>
<td><div class="student-row">👤 Emma K.</div></td>
<td><span class="badge b-on">Reflect</span></td>
<td><div class="progress-bar"><div class="progress-fill" style="width:95%;background:var(--moss)"></div></div></td>
<td>21:08</td>
</tr>
</tbody>
</table>
</div>
<!-- Insights -->
<div class="card">
<h3>💡 Erkannte Fehlkonzepte</h3>
<div class="alert">
<strong>Ozonloch ≠ Treibhauseffekt</strong><br>
7 Schüler*innen haben in ihrer Vorhersage erwähnt, dass das "Ozonloch" für die Erwärmung verantwortlich sei.
→ Empfehlung: Im Plenum klarstellen.
</div>
<div class="alert">
<strong>Lineare statt logarithmische Beziehung</strong><br>
5 Schüler*innen haben "doppelt so viel CO₂ = doppelt so warm" angenommen.
→ Empfehlung: Klimasensitivität gemeinsam besprechen.
</div>
<div class="alert">
<strong>Albedo nicht verstanden</strong><br>
3 Schüler*innen haben Albedo nicht verändert. → Optionale Vertiefung anbieten.
</div>
<h3 style="margin-top:1rem">🎯 Lernziele-Erreichung (Klasse)</h3>
<div style="font-size:.78rem;margin-top:.4rem">
<div style="display:flex;justify-content:space-between;margin-bottom:.3rem"><span>Treibhauseffekt verstehen</span><strong>83%</strong></div>
<div class="progress-bar" style="width:100%"><div class="progress-fill" style="width:83%;background:var(--moss)"></div></div>
<div style="display:flex;justify-content:space-between;margin:.6rem 0 .3rem"><span>CO₂-Temperatur-Zusammenhang</span><strong>71%</strong></div>
<div class="progress-bar" style="width:100%"><div class="progress-fill" style="width:71%;background:var(--fjord)"></div></div>
<div style="display:flex;justify-content:space-between;margin:.6rem 0 .3rem"><span>Abgrenzung zum Ozonloch</span><strong>54%</strong></div>
<div class="progress-bar" style="width:100%"><div class="progress-fill" style="width:54%;background:var(--sand)"></div></div>
</div>
</div>
</div>
<!-- Module freischaltung -->
<div class="card" style="margin-bottom:1rem">
<h3>⚙️ Module für Klasse 1A freigeschaltet</h3>
<div class="grid grid-2" style="margin-top:.8rem">
<div class="sim-toggle-card">
<div class="sim-toggle-card-icon">🌡️</div>
<div class="sim-toggle-card-info">
<h5>Treibhauseffekt-Simulator</h5>
<p>1. Klasse · 20 min · Schwierigkeit: Standard</p>
</div>
<div class="toggle on"></div>
</div>
<div class="sim-toggle-card">
<div class="sim-toggle-card-icon">🌋</div>
<div class="sim-toggle-card-info">
<h5>Erdbeben-Simulator</h5>
<p>1. Klasse · 25 min · Schwierigkeit: Standard</p>
</div>
<div class="toggle on"></div>
</div>
<div class="sim-toggle-card">
<div class="sim-toggle-card-icon"></div>
<div class="sim-toggle-card-info">
<h5>Energiemix-Simulator</h5>
<p>2. Klasse · 25 min · Erst nächstes Jahr</p>
</div>
<div class="toggle"></div>
</div>
<div class="sim-toggle-card">
<div class="sim-toggle-card-icon">🏗️</div>
<div class="sim-toggle-card-info">
<h5>Raumplanung Gemeinde</h5>
<p>3. Klasse · 45 min · Erst in 2 Jahren</p>
</div>
<div class="toggle"></div>
</div>
</div>
</div>
<!-- Live abstimmung -->
<div class="card">
<h3>🗳️ Live-Abstimmung starten</h3>
<p style="font-size:.85rem;color:var(--text2);margin:.4rem 0 .8rem">Stelle deiner Klasse eine Frage. Das Ergebnis fließt direkt in die laufende Simulation ein.</p>
<div style="display:flex;gap:.5rem">
<input type="text" placeholder="z.B.: Sollten wir die CO₂-Werte von 2050 simulieren?" style="flex:1;padding:.6rem 1rem;border:1px solid rgba(0,0,0,.1);border-radius:10px;font-family:inherit;font-size:.85rem">
<button class="btn btn-p">Abstimmung starten</button>
</div>
</div>
</main>
</div>
<script>
// Toggle functionality
document.querySelectorAll('.toggle').forEach(t => {
t.addEventListener('click', () => t.classList.toggle('on'))
})
</script>
</body>
</html>
@@ -1,239 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Energiewende-Planer*in</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="assets/fonts/inter.css">
<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.5; }
.nav { padding:.6rem 1.2rem; display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid rgba(0,0,0,.05); background:var(--white); }
.nav-brand { display:flex; align-items:center; gap:.5rem; font-weight:800; font-size:1rem; color:var(--fjord); text-decoration:none; }
.nav-brand img { width:28px; height:28px; border-radius:6px; }
.nav-actions { display:flex; gap:.4rem; }
.nav-btn { padding:.4rem .8rem; border:1px solid rgba(0,0,0,.08); border-radius:8px; background:var(--white); color:var(--text2); font-size:.78rem; font-weight:600; cursor:pointer; text-decoration:none; }
.nav-btn:hover { background:var(--fjord-l); border-color:var(--fjord); color:var(--fjord); }
.game-layout { display:grid; grid-template-columns:280px 1fr 300px; gap:.8rem; padding:.8rem; max-width:1400px; margin:0 auto; align-items:start; }
.panel { background:var(--white); border-radius:12px; border:1px solid rgba(0,0,0,.05); padding:.9rem; box-shadow:0 2px 8px rgba(0,0,0,.03); }
.panel-h { font-size:.66rem; font-weight:700; color:var(--fjord); text-transform:uppercase; letter-spacing:.06em; margin-bottom:.5rem; }
.left { display:flex; flex-direction:column; gap:.8rem; }
.resource { display:flex; align-items:center; gap:.6rem; padding:.4rem .2rem; border-bottom:1px solid rgba(0,0,0,.04); }
.resource:last-child { border-bottom:none; }
.resource-icon { font-size:1.4rem; width:28px; text-align:center; }
.resource-info { flex:1; min-width:0; }
.resource-name { font-size:.7rem; color:var(--text3); font-weight:500; }
.resource-val { font-size:.95rem; font-weight:700; color:var(--text); }
.goals .goal { padding:.4rem 0; border-bottom:1px solid rgba(0,0,0,.04); }
.goals .goal:last-child { border:0; }
.goal-row { display:flex; align-items:center; gap:.4rem; font-size:.78rem; }
.goal-check { width:14px; height:14px; border:1.5px solid var(--text3); border-radius:3px; display:flex; align-items:center; justify-content:center; font-size:.6rem; flex-shrink:0; }
.goal-check.done { background:var(--moss); border-color:var(--moss); color:#fff; }
.goal-bar { height:3px; background:#e8e5dc; border-radius:2px; margin-top:.3rem; overflow:hidden; }
.goal-bar-fill { height:100%; background:var(--moss); transition:width .3s; }
.center { display:flex; flex-direction:column; gap:.6rem; }
.canvas-wrap { background:var(--white); border-radius:14px; border:1px solid rgba(0,0,0,.05); overflow:hidden; box-shadow:0 4px 16px rgba(0,0,0,.05); position:relative; min-height:440px; }
.tutorial-overlay { position:absolute; inset:0; background:rgba(15,30,40,.85); backdrop-filter:blur(8px); display:flex; align-items:center; justify-content:center; z-index:10; padding:1.5rem; }
.tutorial-card { background:var(--white); border-radius:16px; padding:1.5rem 1.8rem; max-width:500px; box-shadow:0 20px 60px rgba(0,0,0,.3); }
.tutorial-card h3 { font-size:1.2rem; font-weight:800; margin-bottom:.6rem; color:var(--fjord); }
.tutorial-card p { font-size:.88rem; color:var(--text2); white-space:pre-line; margin-bottom:1rem; }
.tutorial-card .progress-dots { display:flex; gap:.3rem; justify-content:center; margin:.8rem 0; }
.dot { width:8px; height:8px; border-radius:50%; background:#dadad0; }
.dot.active { background:var(--fjord); }
.tut-btn { width:100%; padding:.7rem; background:var(--fjord); color:#fff; border:none; border-radius:10px; font-weight:700; font-size:.9rem; cursor:pointer; }
.tut-btn:hover { background:var(--fjord-d); }
.speed-bar { display:flex; gap:.3rem; padding:.5rem; background:var(--white); border-radius:10px; border:1px solid rgba(0,0,0,.05); }
.speed-btn { flex:1; padding:.5rem; border:none; background:transparent; color:var(--text2); font-size:.8rem; font-weight:600; cursor:pointer; border-radius:6px; }
.speed-btn:hover { background:#f0eeea; }
.speed-btn.active { background:var(--fjord); color:#fff; }
.graphs { display:grid; grid-template-columns:1fr 1fr; gap:.6rem; }
.graph-card { background:var(--white); border-radius:10px; border:1px solid rgba(0,0,0,.05); padding:.6rem; }
.graph-title { font-size:.65rem; color:var(--text3); font-weight:600; text-transform:uppercase; letter-spacing:.06em; margin-bottom:.2rem; }
.graph-svg { width:100%; height:50px; }
.right { display:flex; flex-direction:column; gap:.8rem; }
.measure-card { display:flex; gap:.6rem; padding:.6rem; border-radius:10px; border:1px solid rgba(0,0,0,.06); margin-bottom:.4rem; cursor:pointer; transition:all .2s; background:var(--white); }
.measure-card:hover { border-color:var(--fjord); background:var(--fjord-l); }
.measure-card.disabled { opacity:.5; cursor:not-allowed; }
.measure-card.disabled:hover { border-color:rgba(0,0,0,.06); background:var(--white); }
.measure-icon { font-size:1.5rem; width:32px; text-align:center; }
.measure-info { flex:1; min-width:0; }
.measure-name { font-size:.8rem; font-weight:700; }
.measure-desc { font-size:.66rem; color:var(--text3); line-height:1.3; }
.measure-stats { display:flex; gap:.3rem; flex-wrap:wrap; margin-top:.2rem; }
.measure-stat { font-size:.6rem; padding:1px 5px; border-radius:4px; background:#f0eeea; color:var(--text3); font-weight:600; }
.measure-cost { background:var(--sand-l); color:var(--sand); }
.measure-reduction { background:var(--moss-l); color:var(--moss); }
.measure-protection { background:var(--fjord-l); color:var(--fjord); }
.measure-capacity { background:#e8e3f2; color:#7a5ea8; }
.measure-quality { background:var(--coral-l); color:var(--danger); }
.measure-neutral { background:#f0eeea; color:var(--text3); }
.events-list { max-height:180px; overflow-y:auto; }
.event { padding:.4rem .5rem; border-radius:8px; margin-bottom:.3rem; font-size:.74rem; line-height:1.3; }
.event-info { background:#f0eeea; color:var(--text2); }
.event-success { background:var(--moss-l); color:var(--moss); }
.event-warning { background:var(--sand-l); color:var(--sand); }
.event-danger { background:var(--coral-l); color:var(--danger); }
.end-screen { position:fixed; inset:0; background:rgba(15,30,40,.9); backdrop-filter:blur(10px); display:flex; align-items:center; justify-content:center; z-index:100; padding:2rem; }
.end-card { background:var(--white); border-radius:20px; padding:2rem 2.5rem; max-width:500px; text-align:center; box-shadow:0 30px 80px rgba(0,0,0,.4); }
.end-icon { font-size:4rem; margin-bottom:.5rem; }
.end-card h2 { font-size:1.8rem; font-weight:900; letter-spacing:-.02em; margin-bottom:.3rem; }
.end-card .end-summary { color:var(--text2); margin-bottom:1rem; }
.end-stats { display:grid; grid-template-columns:1fr 1fr; gap:.8rem; margin:1rem 0; }
.end-stat { background:#f7f6f3; border-radius:10px; padding:.8rem; }
.end-stat-val { font-size:1.4rem; font-weight:800; color:var(--fjord); }
.end-stat-lbl { font-size:.7rem; color:var(--text3); text-transform:uppercase; }
@media (max-width: 1100px) {
.game-layout { grid-template-columns:1fr; }
.left, .right { order:2; }
}
</style>
</head>
<body>
<nav class="nav">
<a href="index.html" class="nav-brand"><img src="assets/img/logo.png" alt="">GeoGraSim · Energiewende</a>
<div class="nav-actions">
<button class="nav-btn" id="btn-save">💾 Speichern</button>
<button class="nav-btn" id="btn-load">📂 Laden</button>
<button class="nav-btn" id="btn-finish">⏹ Beenden</button>
<button class="nav-btn" id="btn-reset" title="Stand löschen und neu starten">🔄 Reset</button>
<a href="index.html" class="nav-btn">← Zurück</a>
</div>
</nav>
<div class="game-layout">
<aside class="left">
<div class="panel">
<div class="panel-h">📊 Status</div>
<div id="resources"></div>
</div>
<div class="panel goals">
<div class="panel-h">🎯 Ziele</div>
<div id="goals"></div>
</div>
</aside>
<main class="center">
<div class="canvas-wrap" id="canvas-wrap">
<div class="tutorial-overlay" id="tutorial">
<div class="tutorial-card">
<h3 id="tut-title"></h3>
<p id="tut-text"></p>
<div class="progress-dots" id="tut-dots"></div>
<button class="tut-btn" id="tut-next">Weiter →</button>
</div>
</div>
</div>
<div class="speed-bar">
<button class="speed-btn" data-speed="0"></button>
<button class="speed-btn active" data-speed="1">▶ Normal</button>
<button class="speed-btn" data-speed="2">⏩ Schnell</button>
<button class="speed-btn" data-speed="4">⏭ Sehr schnell</button>
</div>
<div class="graphs">
<div class="graph-card">
<div class="graph-title">🌱 Erneuerbar-Anteil</div>
<svg class="graph-svg" id="graph-renewable"></svg>
</div>
<div class="graph-card">
<div class="graph-title">🌫 CO₂-Ausstoß</div>
<svg class="graph-svg" id="graph-co2"></svg>
</div>
<div class="graph-card">
<div class="graph-title">⚡ Erzeugung vs. Bedarf</div>
<svg class="graph-svg" id="graph-supply"></svg>
</div>
<div class="graph-card">
<div class="graph-title">💰 Budget</div>
<svg class="graph-svg" id="graph-budget"></svg>
</div>
</div>
</main>
<aside class="right">
<div class="panel">
<div class="panel-h">⚡ Kraftwerke bauen</div>
<div id="measures"></div>
</div>
<div class="panel">
<div class="panel-h">📰 Ereignisse</div>
<div class="events-list" id="events"></div>
</div>
</aside>
</div>
<div id="end-screen-host"></div>
<script type="module">
import { EnergiemixGame, PLANT_TYPES } from './src/sims/sim-08-energiemix/game.ts'
import { EnergiemixRenderer } from './src/sims/sim-08-energiemix/game-renderer.ts'
import { GameUI } from './src/ui/game-ui.ts'
const game = new EnergiemixGame()
const shopItems = PLANT_TYPES.map(p => {
const badges = []
if (p.capacityMW > 0) {
badges.push({ label: `${p.capacityMW} MW`, type: 'capacity' })
badges.push({ label: `CF ${(p.capacityFactor * 100).toFixed(0)}%`, type: 'neutral' })
}
if (p.renewable) badges.push({ label: '🌱 erneuerbar', type: 'reduction' })
if (p.co2PerKWh > 300) badges.push({ label: `${p.co2PerKWh} g CO₂/kWh`, type: 'quality' })
else if (p.co2PerKWh > 0 && p.capacityMW > 0) badges.push({ label: `${p.co2PerKWh} g CO₂/kWh`, type: 'neutral' })
if (p.flexible && p.capacityMW > 0) badges.push({ label: '🔄 flexibel', type: 'protection' })
if (p.storage) badges.push({ label: `🔋 ${p.storage} MW Speicher`, type: 'protection' })
return {
id: p.id,
name: p.name,
emoji: p.emoji,
description: p.description,
cost: p.cost,
upkeep: p.upkeep,
badges,
}
})
new GameUI({
game,
Renderer: EnergiemixRenderer,
shopItems,
onBuy: (id) => game.buyPlant(id),
graphs: [
{ id: 'graph-renewable', title: 'Erneuerbar', field: 'renewable', yMin: 0, yMax: 100, color: '#5a8a5e', format: v => `${v.toFixed(0)}%` },
{ id: 'graph-co2', title: 'CO₂', field: 'co2', yMin: 0, yMax: 5000, color: '#8a7868' },
{ id: 'graph-supply', title: 'Erzeugung', field: 'supply', yMin: 0, yMax: 3000, color: '#4a7c8a' },
{ id: 'graph-budget', title: 'Budget', field: 'budget', yMin: -300, yMax: 2000, color: '#c4a35a' },
],
saveKey: 'energiemix-save',
yearOffset: 2025,
})
</script>
</body>
</html>
@@ -1,230 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Stadtplaner*in in Erdbebenregion</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="assets/fonts/inter.css">
<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.5; }
.nav { padding:.6rem 1.2rem; display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid rgba(0,0,0,.05); background:var(--white); }
.nav-brand { display:flex; align-items:center; gap:.5rem; font-weight:800; font-size:1rem; color:var(--fjord); text-decoration:none; }
.nav-brand img { width:28px; height:28px; border-radius:6px; }
.nav-actions { display:flex; gap:.4rem; }
.nav-btn { padding:.4rem .8rem; border:1px solid rgba(0,0,0,.08); border-radius:8px; background:var(--white); color:var(--text2); font-size:.78rem; font-weight:600; cursor:pointer; text-decoration:none; }
.nav-btn:hover { background:var(--fjord-l); border-color:var(--fjord); color:var(--fjord); }
.game-layout { display:grid; grid-template-columns:280px 1fr 280px; gap:.8rem; padding:.8rem; max-width:1400px; margin:0 auto; align-items:start; }
.panel { background:var(--white); border-radius:12px; border:1px solid rgba(0,0,0,.05); padding:.9rem; box-shadow:0 2px 8px rgba(0,0,0,.03); }
.panel-h { font-size:.66rem; font-weight:700; color:var(--fjord); text-transform:uppercase; letter-spacing:.06em; margin-bottom:.5rem; }
.left { display:flex; flex-direction:column; gap:.8rem; }
.resource { display:flex; align-items:center; gap:.6rem; padding:.4rem .2rem; border-bottom:1px solid rgba(0,0,0,.04); }
.resource:last-child { border-bottom:none; }
.resource-icon { font-size:1.4rem; width:28px; text-align:center; }
.resource-info { flex:1; min-width:0; }
.resource-name { font-size:.7rem; color:var(--text3); font-weight:500; }
.resource-val { font-size:.95rem; font-weight:700; color:var(--text); }
.goals .goal { padding:.4rem 0; border-bottom:1px solid rgba(0,0,0,.04); }
.goals .goal:last-child { border:0; }
.goal-row { display:flex; align-items:center; gap:.4rem; font-size:.78rem; }
.goal-check { width:14px; height:14px; border:1.5px solid var(--text3); border-radius:3px; display:flex; align-items:center; justify-content:center; font-size:.6rem; flex-shrink:0; }
.goal-check.done { background:var(--moss); border-color:var(--moss); color:#fff; }
.goal-bar { height:3px; background:#e8e5dc; border-radius:2px; margin-top:.3rem; overflow:hidden; }
.goal-bar-fill { height:100%; background:var(--moss); transition:width .3s; }
.center { display:flex; flex-direction:column; gap:.6rem; }
.canvas-wrap { background:var(--white); border-radius:14px; border:1px solid rgba(0,0,0,.05); overflow:hidden; box-shadow:0 4px 16px rgba(0,0,0,.05); position:relative; min-height:440px; }
.tutorial-overlay { position:absolute; inset:0; background:rgba(15,30,40,.85); backdrop-filter:blur(8px); display:flex; align-items:center; justify-content:center; z-index:10; padding:1.5rem; }
.tutorial-card { background:var(--white); border-radius:16px; padding:1.5rem 1.8rem; max-width:480px; box-shadow:0 20px 60px rgba(0,0,0,.3); }
.tutorial-card h3 { font-size:1.2rem; font-weight:800; margin-bottom:.6rem; color:var(--fjord); }
.tutorial-card p { font-size:.88rem; color:var(--text2); white-space:pre-line; margin-bottom:1rem; }
.tutorial-card .progress-dots { display:flex; gap:.3rem; justify-content:center; margin:.8rem 0; }
.dot { width:8px; height:8px; border-radius:50%; background:#dadad0; }
.dot.active { background:var(--fjord); }
.tut-btn { width:100%; padding:.7rem; background:var(--fjord); color:#fff; border:none; border-radius:10px; font-weight:700; font-size:.9rem; cursor:pointer; }
.tut-btn:hover { background:var(--fjord-d); }
.speed-bar { display:flex; gap:.3rem; padding:.5rem; background:var(--white); border-radius:10px; border:1px solid rgba(0,0,0,.05); }
.speed-btn { flex:1; padding:.5rem; border:none; background:transparent; color:var(--text2); font-size:.8rem; font-weight:600; cursor:pointer; border-radius:6px; }
.speed-btn:hover { background:#f0eeea; }
.speed-btn.active { background:var(--fjord); color:#fff; }
.graphs { display:grid; grid-template-columns:1fr 1fr; gap:.6rem; }
.graph-card { background:var(--white); border-radius:10px; border:1px solid rgba(0,0,0,.05); padding:.6rem; }
.graph-title { font-size:.65rem; color:var(--text3); font-weight:600; text-transform:uppercase; letter-spacing:.06em; margin-bottom:.2rem; }
.graph-svg { width:100%; height:50px; }
.right { display:flex; flex-direction:column; gap:.8rem; }
.measure-card { display:flex; gap:.6rem; padding:.6rem; border-radius:10px; border:1px solid rgba(0,0,0,.06); margin-bottom:.4rem; cursor:pointer; transition:all .2s; background:var(--white); }
.measure-card:hover { border-color:var(--fjord); background:var(--fjord-l); }
.measure-card.disabled { opacity:.5; cursor:not-allowed; }
.measure-card.disabled:hover { border-color:rgba(0,0,0,.06); background:var(--white); }
.measure-icon { font-size:1.5rem; width:32px; text-align:center; }
.measure-info { flex:1; min-width:0; }
.measure-name { font-size:.8rem; font-weight:700; }
.measure-desc { font-size:.66rem; color:var(--text3); line-height:1.3; }
.measure-stats { display:flex; gap:.3rem; flex-wrap:wrap; margin-top:.2rem; }
.measure-stat { font-size:.6rem; padding:1px 5px; border-radius:4px; background:#f0eeea; color:var(--text3); font-weight:600; }
.measure-cost { background:var(--sand-l); color:var(--sand); }
.measure-reduction { background:var(--moss-l); color:var(--moss); }
.measure-protection { background:var(--fjord-l); color:var(--fjord); }
.measure-capacity { background:#e8e3f2; color:#7a5ea8; }
.measure-quality { background:var(--coral-l); color:var(--danger); }
.measure-neutral { background:#f0eeea; color:var(--text3); }
.events-list { max-height:180px; overflow-y:auto; }
.event { padding:.4rem .5rem; border-radius:8px; margin-bottom:.3rem; font-size:.74rem; line-height:1.3; }
.event-info { background:#f0eeea; color:var(--text2); }
.event-success { background:var(--moss-l); color:var(--moss); }
.event-warning { background:var(--sand-l); color:var(--sand); }
.event-danger { background:var(--coral-l); color:var(--danger); }
.end-screen { position:fixed; inset:0; background:rgba(15,30,40,.9); backdrop-filter:blur(10px); display:flex; align-items:center; justify-content:center; z-index:100; padding:2rem; }
.end-card { background:var(--white); border-radius:20px; padding:2rem 2.5rem; max-width:500px; text-align:center; box-shadow:0 30px 80px rgba(0,0,0,.4); }
.end-icon { font-size:4rem; margin-bottom:.5rem; }
.end-card h2 { font-size:1.8rem; font-weight:900; letter-spacing:-.02em; margin-bottom:.3rem; }
.end-card .end-summary { color:var(--text2); margin-bottom:1rem; }
.end-stats { display:grid; grid-template-columns:1fr 1fr; gap:.8rem; margin:1rem 0; }
.end-stat { background:#f7f6f3; border-radius:10px; padding:.8rem; }
.end-stat-val { font-size:1.4rem; font-weight:800; color:var(--fjord); }
.end-stat-lbl { font-size:.7rem; color:var(--text3); text-transform:uppercase; }
@media (max-width: 1100px) {
.game-layout { grid-template-columns:1fr; }
.left, .right { order:2; }
}
</style>
</head>
<body>
<nav class="nav">
<a href="index.html" class="nav-brand"><img src="assets/img/logo.png" alt="">GeoGraSim · Erdbebenregion</a>
<div class="nav-actions">
<button class="nav-btn" id="btn-save">💾 Speichern</button>
<button class="nav-btn" id="btn-load">📂 Laden</button>
<button class="nav-btn" id="btn-finish">⏹ Beenden</button>
<button class="nav-btn" id="btn-reset" title="Stand löschen und neu starten">🔄 Reset</button>
<a href="index.html" class="nav-btn">← Zurück</a>
</div>
</nav>
<div class="game-layout">
<aside class="left">
<div class="panel">
<div class="panel-h">📊 Status</div>
<div id="resources"></div>
</div>
<div class="panel goals">
<div class="panel-h">🎯 Ziele</div>
<div id="goals"></div>
</div>
</aside>
<main class="center">
<div class="canvas-wrap" id="canvas-wrap">
<div class="tutorial-overlay" id="tutorial">
<div class="tutorial-card">
<h3 id="tut-title"></h3>
<p id="tut-text"></p>
<div class="progress-dots" id="tut-dots"></div>
<button class="tut-btn" id="tut-next">Weiter →</button>
</div>
</div>
</div>
<div class="speed-bar">
<button class="speed-btn" data-speed="0"></button>
<button class="speed-btn active" data-speed="1">▶ Normal</button>
<button class="speed-btn" data-speed="2">⏩ Schnell</button>
<button class="speed-btn" data-speed="4">⏭ Sehr schnell</button>
</div>
<div class="graphs">
<div class="graph-card">
<div class="graph-title">👥 Bevölkerung</div>
<svg class="graph-svg" id="graph-pop"></svg>
</div>
<div class="graph-card">
<div class="graph-title">🏠 Wohnraum</div>
<svg class="graph-svg" id="graph-housed"></svg>
</div>
<div class="graph-card">
<div class="graph-title">💰 Budget</div>
<svg class="graph-svg" id="graph-budget"></svg>
</div>
<div class="graph-card">
<div class="graph-title">🕯️ Opfer (kumulativ)</div>
<svg class="graph-svg" id="graph-deaths"></svg>
</div>
</div>
</main>
<aside class="right">
<div class="panel">
<div class="panel-h">🏗 Häuser bauen</div>
<div id="measures"></div>
</div>
<div class="panel">
<div class="panel-h">📰 Ereignisse</div>
<div class="events-list" id="events"></div>
</div>
</aside>
</div>
<div id="end-screen-host"></div>
<script type="module">
import { ErdbebenGame, BUILDING_TYPES } from './src/sims/sim-07-erdbeben/game.ts'
import { ErdbebenRenderer } from './src/sims/sim-07-erdbeben/game-renderer.ts'
import { GameUI } from './src/ui/game-ui.ts'
const game = new ErdbebenGame()
const shopItems = BUILDING_TYPES.map(b => ({
id: b.id,
name: b.name,
emoji: b.emoji,
description: b.description,
cost: b.cost,
upkeep: b.upkeep,
badges: [
b.capacity > 0 ? { label: `👥 ${b.capacity} Plätze`, type: 'capacity' } : null,
{ label: `🛡 Q ${(b.quality * 100).toFixed(0)}%`, type: b.quality >= 0.6 ? 'protection' : 'quality' },
].filter(Boolean),
}))
new GameUI({
game,
Renderer: ErdbebenRenderer,
shopItems,
onBuy: (id) => game.buyBuilding(id),
graphs: [
{ id: 'graph-pop', title: 'Bevölkerung', field: 'population', yMin: 0, yMax: 6000, color: '#4a7c8a' },
{ id: 'graph-housed', title: 'Wohnraum', field: 'housed', yMin: 0, yMax: 6000, color: '#5a8a5e' },
{ id: 'graph-budget', title: 'Budget', field: 'budget', yMin: -300, yMax: 1500, color: '#c4a35a' },
{ id: 'graph-deaths', title: 'Opfer', field: 'deaths', yMin: 0, yMax: 500, color: '#b04a3a' },
],
saveKey: 'erdbeben-save',
yearOffset: 1975,
})
</script>
</body>
</html>
@@ -1,872 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Flussmanagement</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="assets/fonts/inter.css">
<style>
*,*::before,*::after{margin:0;padding:0;box-sizing:border-box}
:root{--bg:#f7f6f3;--white:#fff;--text:#1a1a1a;--text2:#4a4a4a;--text3:#8a8a8a;--fjord:#4a7c8a;--fjord-l:#dae8ec;--fjord-d:#3a6470;--moss:#5a8a5e;--moss-l:#dceadd;--sand:#c4a35a;--coral:#c07a6b}
html,body{height:100%;overflow:hidden}
body{font-family:'Inter',system-ui,sans-serif;background:var(--bg);color:var(--text);display:flex;flex-direction:column}
.nav{padding:.4rem .8rem;display:flex;justify-content:space-between;align-items:center;border-bottom:1px solid rgba(0,0,0,.05);background:var(--white);flex-shrink:0}
.nav-brand{display:flex;align-items:center;gap:.4rem;font-weight:800;font-size:.9rem;color:var(--fjord);text-decoration:none}
.nav-brand img{width:24px;height:24px;border-radius:5px}
.nav-btn{padding:.25rem .6rem;border:1px solid rgba(0,0,0,.08);border-radius:6px;background:var(--white);color:var(--text2);font-size:.68rem;font-weight:600;cursor:pointer;text-decoration:none}
.nav-btn:hover{background:var(--fjord-l);color:var(--fjord)}
.main{flex:1;display:grid;grid-template-columns:190px 1fr 200px;gap:.4rem;padding:.4rem;min-height:0;overflow:hidden}
.panel{background:var(--white);border-radius:9px;border:1px solid rgba(0,0,0,.04);padding:.5rem;box-shadow:0 1px 4px rgba(0,0,0,.02);overflow-y:auto}
.panel-h{font-size:.58rem;font-weight:700;color:var(--fjord);text-transform:uppercase;letter-spacing:.05em;margin-bottom:.3rem}
.col-left,.col-right{display:flex;flex-direction:column;gap:.4rem;overflow-y:auto}
.col-center{display:flex;flex-direction:column;gap:.3rem;min-height:0}
.topbar{flex-shrink:0;display:flex;align-items:center;gap:.4rem;background:var(--white);border-radius:8px;padding:.3rem .6rem;border:1px solid rgba(0,0,0,.04);flex-wrap:wrap}
.topbar .stat{font-size:.68rem;font-weight:700;display:flex;align-items:center;gap:.2rem}
.topbar .stat .v{font-size:.85rem}
.topbar .gold .v{color:var(--sand)}
.topbar .yr .v{color:var(--fjord)}
.topbar .inc{font-size:.58rem;color:var(--moss);font-weight:600}
.topbar .wx{font-size:.78rem;padding:.1rem .35rem;border-radius:4px;background:var(--bg);font-weight:600}
.spd{display:flex;gap:.1rem;margin-left:auto}
.spd button{width:26px;height:22px;border:1px solid rgba(0,0,0,.07);border-radius:4px;background:var(--white);font-size:.62rem;font-weight:700;cursor:pointer;display:flex;align-items:center;justify-content:center}
.spd button.on{background:var(--fjord);color:#fff;border-color:var(--fjord)}
.canvas-wrap{flex:1;background:#dde6d4;border-radius:9px;overflow:hidden;position:relative;min-height:200px;cursor:crosshair}
.canvas-wrap canvas{width:100%;height:100%;display:block}
.param{display:flex;align-items:center;gap:.3rem;padding:.18rem 0;border-bottom:1px solid rgba(0,0,0,.02)}.param:last-child{border:none}
.param-i{font-size:.75rem;width:17px;text-align:center}.param-inf{flex:1}
.param-n{font-size:.55rem;color:var(--text3)}.param-bar{height:3.5px;background:#e8e5dc;border-radius:2px;margin-top:1px;overflow:hidden}
.param-bar-f{height:100%;border-radius:2px;transition:width .8s}.param-v{font-size:.62rem;font-weight:700;min-width:17px;text-align:right}
.tool{display:flex;align-items:center;gap:.3rem;padding:.3rem .4rem;border:1.5px solid rgba(0,0,0,.05);border-radius:6px;background:var(--white);cursor:pointer;width:100%;text-align:left;margin-bottom:.18rem;transition:all .12s}
.tool:hover{border-color:var(--fjord);background:var(--fjord-l)}.tool.on{border-color:var(--fjord);background:var(--fjord);color:#fff}
.tool.off{opacity:.3;pointer-events:none;filter:grayscale(100%);background:var(--bg)!important;border-color:rgba(0,0,0,.05)!important;color:var(--text3)!important}
.tool-e{font-size:.85rem}.tool-inf{flex:1}.tool-nm{font-size:.62rem;font-weight:600}.tool-ds{font-size:.5rem;color:var(--text3)}.tool-c{font-size:.52rem;font-weight:600;color:var(--sand)}
.log{font-size:.55rem;padding:.12rem 0;border-bottom:1px solid rgba(0,0,0,.02);color:var(--text2)}.log.bad{color:var(--coral)}.log.good{color:var(--moss)}
.ov{position:fixed;inset:0;background:rgba(0,0,0,.45);display:flex;align-items:center;justify-content:center;z-index:200;backdrop-filter:blur(3px)}
.ov-c{background:var(--white);border-radius:14px;padding:1.4rem;max-width:400px;width:90%;text-align:center}
.ov-c h2{font-size:1rem;font-weight:800;margin-bottom:.2rem}.ov-c p{font-size:.75rem;color:var(--text2);margin-bottom:.5rem;line-height:1.4}
.ov-btn{padding:.4rem 1rem;border:none;border-radius:6px;background:var(--fjord);color:#fff;font-size:.75rem;font-weight:700;cursor:pointer}
.hidden{display:none!important}
@media(max-width:800px){.main{grid-template-columns:1fr}}
</style>
</head>
<body>
<nav class="nav">
<a href="index.html" class="nav-brand"><img src="assets/img/logo.png" alt="">Flussmanagement</a>
<div style="display:flex;gap:.2rem"><button id="btn-reset" class="nav-btn">🔄 Neu</button><a href="index.html" class="nav-btn">← Zurück</a></div>
</nav>
<div id="game" class="main">
<div class="col-left">
<div class="panel"><div class="panel-h">Zustand</div><div id="params"></div></div>
<div class="panel"><div class="panel-h">Verlauf</div><canvas id="graph" style="width:100%;height:90px;display:block;border-radius:6px;background:#f4f2ee"></canvas></div>
<div class="panel"><div class="panel-h">Ereignisse</div><div id="log" style="max-height:100px;overflow-y:auto"></div></div>
</div>
<div class="col-center">
<div class="topbar">
<div class="stat gold">💰 <span class="v" id="h-bud">30</span></div>
<span class="inc" id="h-inc">+0/J</span>
<span class="wx" id="h-wx"></span>
<div class="stat yr">📅 <span class="v" id="h-yr">0</span></div>
<div class="spd"><button data-s="0"></button><button data-s="1" class="on"></button><button data-s="2">▶▶</button><button data-s="4">▶▶▶</button></div>
</div>
<div class="canvas-wrap"><canvas id="cv"></canvas></div>
</div>
<div class="col-right">
<div class="panel"><div class="panel-h">Werkzeug</div><div id="tools"></div></div>
<div class="panel"><div class="panel-h">Info</div><div id="info" style="font-size:.6rem;color:var(--text2)">Maus über die Karte bewegen.</div></div>
</div>
</div>
<div id="ov-intro" class="ov">
<div class="ov-c">
<div style="font-size:1.8rem;margin-bottom:.15rem">🏞️</div>
<h2>Flussmanagement</h2>
<p>Der Fluss lebt — er ändert jedes Jahr seinen Lauf! Baue Siedlungen und Felder, aber schütze sie mit Deichen. Begradige den Fluss wenn nötig, aber die Natur rächt sich flussabwärts.</p>
<button class="ov-btn" id="btn-go">Los geht's!</button>
</div>
</div>
<div id="ov-end" class="ov hidden">
<div class="ov-c"><h2 id="end-t"></h2><p id="end-p"></p><button class="ov-btn" id="btn-again">Nochmal</button></div>
</div>
<script>
// =====================================================================
// FLUSSMANAGEMENT v3 — Punkt-basierter Fluss mit Kreisen
// Fluss = 16 Punkte (Spaltenposition), verbunden durch Kreise
// Pro Jahr wandert EIN Punkt 1 Feld links/rechts
// =====================================================================
const COLS = 20, ROWS = 16
const MAX_YEARS = 100, MS_PER_TICK = 2500, WX_INTERVAL = 3
// Fluss: Array von 16 Spaltenpositionen (0..COLS-1)
let riverCol = [] // Ganzzahlige Zielpositionen (Spalte)
let riverColSmooth = [] // Smooth-interpolierte Anzeigepositionen (fliessend)
let riverEng = [] // Befestigung pro Segment (0=natur, 1=holz, 2=stein, 3=beton)
let riverRadius = [] // Radius pro Segment (variiert)
// Land-Grid
let land = [] // ROWS x COLS
let tilePop = [], tileCap = [], tileYield = []
let floodIntensity = [] // 0..1 smooth per tile
let tileFloodYears = [] // wie viele Jahre am Stueck ueberschwemmt
// Game
let budget = 30, year = 0, speed = 1, gameOver = false
let tickAccum = 0, wxTimer = 0, selectedTool = null
let eventLog = [], floats = [] // floating emojis
let history = [] // [{year, pop, food, bio, safety, economy}]
const WX = [
{n:'Dürre',e:'☀️',f:0.2,p:.12},{n:'Trocken',e:'🌤️',f:0.4,p:.25},
{n:'Normal',e:'⛅',f:0.8,p:.33},{n:'Regen',e:'🌧️',f:1.5,p:.20},{n:'Starkregen',e:'⛈️',f:2.8,p:.10}
]
let weather = WX[2]
function rollWx(){let r=Math.random(),c=0;for(const w of WX){c+=w.p;if(r<c)return w}return WX[2]}
const TOOLS = [
{id:'inspect',nm:'Experte fragen',e:'🧑‍🏫',ds:'Klicke irgendwo — der Experte erklärt die Lage.',cost:0},
{id:'levee',nm:'Deich',e:'🧱',ds:'Hält Fluss auf. Kann bei Dauerflut brechen.',cost:6},
{id:'field',nm:'Feld',e:'🌾',ds:'Ertrag je nach Feuchtigkeit. Stirbt nach 2J Flut.',cost:4},
{id:'settlement',nm:'Siedlung',e:'🏘️',ds:'Bewohner zahlen Steuern. Fliehen bei Flut.',cost:10},
{id:'forest',nm:'Wald',e:'🌳',ds:'Bremst Erosion, schützt Grundwasser. Trocknet neben Begradigung aus.',cost:5},
{id:'demolish',nm:'Abreißen',e:'🗑️',ds:'Entfernt alles — auch Begradigung!',cost:2},
{id:'straighten',nm:'Begradigen',e:'📏',ds:'Zieht Fluss zur Mitte. Fixiert ihn dort. Trocknet Umgebung aus!',cost:60},
]
function initGame() {
// Fluss: startet als Maeander
riverCol = [8,9,10,11,10,9,8,7,8,9,10,11,10,9,8,7]
riverColSmooth = riverCol.map(c => c) // Kopie fuer Animation
riverEng = new Array(ROWS).fill(0)
// Variierende Radien — Fluss ist nicht ueberall gleich breit
riverRadius = riverCol.map((_, i) => 0.8 + Math.sin(i * 0.9) * 0.3 + Math.random() * 0.2)
land = []; floodIntensity = []; tilePop = []; tileCap = []; tileYield = []; tileFloodYears = []
for (let r = 0; r < ROWS; r++) {
land[r] = []; floodIntensity[r] = []; tilePop[r] = []; tileCap[r] = []; tileYield[r] = []; tileFloodYears[r] = []
for (let c = 0; c < COLS; c++) {
floodIntensity[r][c] = 0; tilePop[r][c] = 0; tileCap[r][c] = 0; tileYield[r][c] = 0; tileFloodYears[r][c] = 0
// Wald weit vom Fluss, Wiese nah dran
const dist = Math.abs(c - riverCol[r])
if (dist <= 1) land[r][c] = 'meadow'
else if (dist > 4 && Math.random() < 0.5) land[r][c] = 'forest'
else land[r][c] = 'meadow'
}
}
// Startgebaeude
land[4][13] = 'settlement'; land[5][13] = 'field'; land[5][14] = 'field'
tilePop[4][13] = 3; tileCap[4][13] = 8
budget = 30; year = 0; speed = 1; gameOver = false
weather = WX[2]; wxTimer = 0; tickAccum = 0
eventLog = [{t:'🏞️ Willkommen! Der Fluss wandert — plane voraus!',c:'good'}]; history = []
selectedTool = null; floats = []
}
// === FLUSS-GEOMETRIE ===
// Distance-Cache: wird einmal pro Tick aktualisiert statt pro Frame pro Tile
let distCache = []
function rebuildDistCache() {
for (let r = 0; r < ROWS; r++) {
if (!distCache[r]) distCache[r] = []
for (let c = 0; c < COLS; c++) distCache[r][c] = _calcDist(r, c)
}
}
function distToRiver(r, c) {
if (distCache[r] && distCache[r][c] !== undefined) return distCache[r][c]
return _calcDist(r, c)
}
function _calcDist(r, c) {
let minD = 999
for (let i = 0; i < ROWS; i++) {
const rc = riverColSmooth[i]
if (i < ROWS - 1) {
const rc2 = riverColSmooth[i + 1]
// Punkt-zu-Segment Abstand (vereinfacht: nehme naechsten Endpunkt)
const d1 = Math.sqrt((r - i) ** 2 + (c - rc) ** 2)
const d2 = Math.sqrt((r - (i + 1)) ** 2 + (c - rc2) ** 2)
minD = Math.min(minD, d1, d2)
} else {
minD = Math.min(minD, Math.sqrt((r - i) ** 2 + (c - rc) ** 2))
}
}
return minD
}
function isRiverTile(r, c) {
return distToRiver(r, c) < 1.3
}
// === TICK ===
function tick() {
if (gameOver) return
year++
rebuildDistCache() // Cache neu bauen (einmal pro Tick statt pro Frame pro Tile)
// EventLog cappen
if (eventLog.length > 50) eventLog.length = 50
// 1. Einkommen
let income = 0, totalPop = 0, totalFood = 0
for (let r = 0; r < ROWS; r++) for (let c = 0; c < COLS; c++) {
const dist = distToRiver(r, c)
const moisture = Math.max(0, 1 - Math.abs(dist - 2.5) / 3) // optimal bei ~2.5 Felder Abstand
const fi = floodIntensity[r][c]
if (land[r][c] === 'field') {
// Begradigung in der Naehe trocknet Feld aus
let dryPenalty = 0
for (let i = Math.max(0, r-1); i <= Math.min(ROWS-1, r+1); i++) {
if (riverEng[i] > 0) dryPenalty = Math.max(dryPenalty, riverEng[i] * 0.25)
}
const effMoisture = Math.max(0, moisture - dryPenalty)
// Ertrag: Basis-Feuchtigkeit + braucht Arbeiter in der Naehe
let workerBonus = 0
for (let dr=-2;dr<=2;dr++) for(let dc=-2;dc<=2;dc++){
const nr=r+dr,nc=c+dc
if(nr>=0&&nr<ROWS&&nc>=0&&nc<COLS&&land[nr][nc]==='settlement')
workerBonus += tilePop[nr][nc] * 0.15
}
workerBonus = Math.min(1, workerBonus) // max 100% Arbeiterbonus
const baseYield = (1 + effMoisture * 5) * (1 - fi * 0.9)
const y = Math.round(Math.max(0, Math.min(8, baseYield * (0.3 + workerBonus * 0.7))))
tileYield[r][c] = y; income += y * 0.5; totalFood += y
}
if (land[r][c] === 'settlement') {
tileCap[r][c] = 8
const cur = tilePop[r][c]
// Zuzug: braucht Nahrung UND trockenes Haus
const hasFood = totalFood > totalPop * 0.4
if (cur < 8 && hasFood && fi < 0.15) {
tilePop[r][c] = Math.min(8, cur + (Math.random() < 0.35 ? 1 : 0))
}
// Feuchtigkeit → Bewohner werden krank, fliehen langsam
if (fi > 0.2 && cur > 0 && Math.random() < fi * 0.2) {
tilePop[r][c] = Math.max(0, cur - 1)
}
totalPop += tilePop[r][c]
income += tilePop[r][c] * 0.8
}
}
budget += Math.round(income)
// 2. Wetter
wxTimer++; if (wxTimer >= WX_INTERVAL) { wxTimer = 0; weather = rollWx() }
// 3. FLUSS WANDERT — EIN Punkt pro Jahr
const idx = Math.floor(Math.random() * ROWS)
if (riverEng[idx] === 0) { // nur wenn nicht befestigt
const dir = Math.random() < 0.5 ? -1 : 1
const newCol = riverCol[idx] + dir
// Max 3 Felder Abstand zum Nachbarn
const prevOk = idx === 0 || Math.abs(newCol - riverCol[idx - 1]) <= 3
const nextOk = idx === ROWS - 1 || Math.abs(newCol - riverCol[idx + 1]) <= 3
if (newCol >= 1 && newCol < COLS - 1 && prevOk && nextOk) {
riverCol[idx] = newCol
// Was auf dem neuen Feld stand → zerstoeren
if (land[idx][newCol] === 'settlement') {
land[idx][newCol] = 'ruin'
eventLog.push({t: `🌊 Fluss verschlingt Siedlung! (Zeile ${idx+1})`, c: 'bad'})
} else if (land[idx][newCol] === 'field') {
land[idx][newCol] = 'meadow'
eventLog.push({t: `🌊 Fluss überspült Feld (Zeile ${idx+1})`, c: 'bad'})
} else if (land[idx][newCol] === 'levee') {
// Deich haelt — Fluss wird zurueckgedraengt
riverCol[idx] -= dir
eventLog.push({t: `🧱 Deich hält! (Zeile ${idx+1})`, c: 'good'})
}
}
}
// 4. Hochwasser + Trockenheit durch Begradigung
for (let r = 0; r < ROWS; r++) for (let c = 0; c < COLS; c++) {
const dist = distToRiver(r, c)
let target = 0
if (weather.f >= 1.0 && dist < 4) {
const base = Math.max(0, 1 - dist / 4)
const leveeProt = land[r][c] === 'levee' ? 0.9 : (hasLeveeNear(r, c) ? 0.5 : 0)
target = base * weather.f * 0.4 * (1 - leveeProt)
}
floodIntensity[r][c] += (target - floodIntensity[r][c]) * 0.2
// Flood-Jahre tracken
if (floodIntensity[r][c] > 0.35) {
tileFloodYears[r][c] = (tileFloodYears[r][c] || 0) + 1
} else {
tileFloodYears[r][c] = 0
}
// Feld stirbt nach 2 Jahren Dauerflut
if (land[r][c] === 'field' && tileFloodYears[r][c] >= 2) {
land[r][c] = 'meadow'
eventLog.push({t: `🌾💀 Feld ertrunken! (${c+1},${r+1})`, c: 'bad'})
}
// Siedlung: Bewohner fliehen bei Flut, Gebaeude wird Ruine nach 3J
if (land[r][c] === 'settlement' && floodIntensity[r][c] > 0.5 && Math.random() < 0.05) {
land[r][c] = 'ruin'; eventLog.push({t:`🏚️ Siedlung zerstört!`,c:'bad'})
}
// Wald stirbt bei Dauerflut
if (land[r][c] === 'forest' && tileFloodYears[r][c] >= 3) {
land[r][c] = 'dead_tree'
}
// Deich-Erosion bei Dauerflut
if (land[r][c] === 'levee' && floodIntensity[r][c] > 0.4 && Math.random() < 0.08) {
land[r][c] = 'meadow'; eventLog.push({t:'🧱💨 Deich weggespült!',c:'bad'})
}
}
// 4b. Begradigung trocknet Umgebung aus
for (let i = 0; i < ROWS; i++) {
if (riverEng[i] > 0) {
// 2 Felder links und rechts vom begradigten Fluss werden trocken
const rc = riverCol[i]
for (let dc = -3; dc <= 3; dc++) {
const cc = rc + dc
if (cc < 0 || cc >= COLS) continue
if (Math.abs(dc) <= 1) continue // direkt am Fluss ist eh Wasser
// Baeume sterben langsam neben Begradigung
if (land[i][cc] === 'forest' && Math.random() < 0.03 * riverEng[i]) {
land[i][cc] = 'dead_tree'
eventLog.push({t:'🌳💀 Baum vertrocknet neben Begradigung',c:'bad'})
}
// Felder neben Begradigung produzieren weniger (wird in Yield-Berechnung beruecksichtigt)
}
}
}
// 5. Flussbreite bei Hochwasser
for (let i = 0; i < ROWS; i++) {
riverRadius[i] += ((weather.f > 1.2 ? 1.8 : 1.2) - riverRadius[i]) * 0.1
}
// 6. Verfall
for (let r = 0; r < ROWS; r++) for (let c = 0; c < COLS; c++) {
if (land[r][c] === 'ruin' && Math.random() < 0.03) land[r][c] = 'meadow'
if (land[r][c] === 'dead_tree' && Math.random() < 0.03) land[r][c] = 'meadow'
}
// History fuer Graph speichern
const avgEng_=riverEng.reduce((s,v)=>s+v,0)/ROWS
const floodTot=floodIntensity.flat().reduce((s,v)=>s+v,0)/(ROWS*COLS)
const clp=v=>Math.min(100,Math.max(0,Math.round(v)))
let h_sett=0,h_fld=0,h_for=0,h_lev=0,h_ruin=0;for(let rr=0;rr<ROWS;rr++)for(let cc=0;cc<COLS;cc++){const tt=land[rr][cc];if(tt==='settlement')h_sett++;if(tt==='field')h_fld++;if(tt==='forest')h_for++;if(tt==='levee')h_lev++;if(tt==='ruin')h_ruin++}
history.push({
year,
pop:clp(totalPop*5-h_ruin*8),
food:clp(totalFood*1.5),
bio:clp(h_for*4-avgEng_*30-(h_sett+h_fld)*1.5),
safety:clp(15+h_lev*6+avgEng_*8-floodTot*80),
economy:clp(totalPop*3+h_fld*2-h_ruin*5)
})
if (year >= MAX_YEARS) { gameOver = true; showEnd() }
// Wetter-Emojis
if (weather.f >= 1.5) floats.push({x:Math.random(),y:-0.05,e:weather.f>=2.5?'⛈️':'🌧️',t:performance.now()})
if (weather.f <= 0.3) floats.push({x:Math.random()*0.5+0.25,y:-0.05,e:'☀️',t:performance.now()})
renderUI()
}
function hasLeveeNear(r, c) {
for (let dr=-1;dr<=1;dr++) for (let dc=-1;dc<=1;dc++) {
const nr=r+dr,nc=c+dc
if (nr>=0&&nr<ROWS&&nc>=0&&nc<COLS&&land[nr][nc]==='levee') return true
}
return false
}
// === APPLY TOOL ===
function applyAt(gr, gc) {
if (gameOver || !selectedTool || gr<0 || gr>=ROWS || gc<0 || gc>=COLS) return
const t = selectedTool, cur = land[gr][gc]
const onRiver = isRiverTile(gr, gc)
const nearRiver = distToRiver(gr, gc) < 2.5
if (t === 'inspect') {
const d = distToRiver(gr, gc)
const fi = floodIntensity[gr]?.[gc] || 0
const fy = tileFloodYears[gr]?.[gc] || 0
if (onRiver) {
const eng = riverEng[gr]
const engNames = ['natürlich','Holzverbau','Bruchstein','Beton']
let msg = `🌊 Fluss — Befestigung: ${engNames[eng] || 'natürlich'}.`
if (eng > 0) msg += ` Fluss ist hier fixiert. Umgebung trocknet aus.`
else msg += ` Fließt frei — kann jedes Jahr wandern!`
eventLog.push({t: msg, c: ''})
} else if (cur === 'field') {
const yi = tileYield[gr]?.[gc] || 0
let msg = `🌾 Feld — Ertrag: ${yi}/8.`
if (fi > 0.35) msg += ` ⚠️ Abgesoffen! Kaum Ertrag. Noch ${2-fy} Jahr(e) bis es stirbt.`
else if (fi > 0.15) msg += ` 💧 Zu feucht — Ertrag reduziert.`
else if (d > 5) msg += ` 🥵 Sehr trocken — weit vom Fluss. Wenig Ertrag.`
else if (d > 3.5) msg += ` Etwas trocken. Näherer Standort wäre besser.`
else msg += ` 👍 Gute Feuchtigkeit!`
let hasWorkers = false
for(let dr=-2;dr<=2;dr++)for(let dc=-2;dc<=2;dc++){const nr=gr+dr,nc=gc+dc;if(nr>=0&&nr<ROWS&&nc>=0&&nc<COLS&&land[nr][nc]==='settlement'&&tilePop[nr][nc]>0)hasWorkers=true}
if (!hasWorkers) msg += ` ⚠️ Keine Arbeiter! Siedlung in der Nähe nötig.`
eventLog.push({t: msg, c: yi > 4 ? 'good' : yi > 1 ? '' : 'bad'})
} else if (cur === 'settlement') {
const pop = tilePop[gr]?.[gc] || 0
let msg = `🏘️ Siedlung — ${pop}/8 Bewohner.`
if (fi > 0.3) msg += ` 🤒 Feucht! Bewohner werden krank und fliehen.`
else if (fi > 0.1) msg += ` 😰 Etwas feucht. Manche Bewohner sind unwohl.`
else msg += ` Trocken und sicher.`
if (pop < 8) msg += ` Neue Bewohner kommen, wenn genug Nahrung da ist.`
eventLog.push({t: msg, c: fi > 0.2 ? 'bad' : 'good'})
} else if (cur === 'levee') {
let msg = `🧱 Deich.`
if (fi > 0.3) msg += ` ⚠️ Unter Druck! Kann bei Dauerflut brechen.`
else msg += ` Intakt. Schützt dahinterliegende Flächen.`
eventLog.push({t: msg, c: fi > 0.3 ? 'bad' : 'good'})
} else if (cur === 'forest') {
let msg = `🌳 Wald — schützt vor Erosion, speichert Grundwasser.`
let nearStraight = false
for(let i=Math.max(0,gr-1);i<=Math.min(ROWS-1,gr+1);i++){if(riverEng[i]>0)nearStraight=true}
if (nearStraight) msg += ` ⚠️ Neben Begradigung — trocknet aus, Baum in Gefahr!`
if (fi > 0.2) msg += ` 💧 Feucht. Bei Dauerflut stirbt der Baum.`
eventLog.push({t: msg, c: nearStraight ? 'bad' : 'good'})
} else if (cur === 'ruin') {
eventLog.push({t: `🏚️ Ruine — ehemaliges Gebäude. Kann abgerissen werden (💰2). Verfällt mit der Zeit.`, c: 'bad'})
} else if (cur === 'dead_tree') {
eventLog.push({t: `🪵 Toter Baum — vertrocknet oder ertrunken. Verrottet langsam.`, c: 'bad'})
} else {
let msg = `🌱 Wiese — freie Fläche.`
if (d < 2.5) msg += ` Nah am Fluss: fruchtbar, aber hochwassergefährdet.`
else if (d < 4) msg += ` Gute Lage für Feld oder Siedlung.`
else msg += ` Weit vom Fluss. Trocken.`
eventLog.push({t: msg, c: ''})
}
renderUI(); return
}
if (t === 'straighten') {
if (!onRiver) return
if (budget < 60) return
// Begradigung: Fluss wird zur Bildmitte (Spalte 10) gezogen
riverEng[gr] = Math.min(3, riverEng[gr] + 1)
riverCol[gr] = COLS / 2 // Mitte
budget -= 60
eventLog.push({t:`📏 Fluss begradigt zur Mitte (Zeile ${gr+1}) — 💰60`,c:''})
} else if (t === 'levee') {
if (onRiver) return
const dRiv = distToRiver(gr, gc)
if (dRiv > 4) { eventLog.push({t:'🧱 Zu weit vom Fluss! Deich muss in Flussnähe stehen.',c:'bad'}); renderUI(); return }
if (cur !== 'meadow' && cur !== 'forest') return
if (budget < 6) return
land[gr][gc] = 'levee'; budget -= 6
} else if (t === 'field') {
if (onRiver) return
if (cur !== 'meadow') return
if (budget < 4) return
land[gr][gc] = 'field'; budget -= 4
// Kontextuelle Rueckmeldung
const d = distToRiver(gr, gc)
if (d < 2.5) eventLog.push({t:'🌾 Feld angelegt — schön nah am Wasser! Guter Ertrag, aber bei Hochwasser gefährdet.',c:'good'})
else if (d < 4) eventLog.push({t:'🌾 Feld angelegt — gute Lage. Genug Feuchtigkeit, sicher vor dem Fluss.',c:'good'})
else eventLog.push({t:'🌾 Feld angelegt — weit vom Fluss! Hier wird es trocken. Ertrag wird gering sein.',c:'bad'})
// Arbeiter-Hinweis
let hasWorkers = false
for(let dr=-2;dr<=2;dr++)for(let dc=-2;dc<=2;dc++){const nr=gr+dr,nc=gc+dc;if(nr>=0&&nr<ROWS&&nc>=0&&nc<COLS&&land[nr][nc]==='settlement'&&tilePop[nr][nc]>0)hasWorkers=true}
if(!hasWorkers) eventLog.push({t:'⚠️ Keine Siedlung in der Nähe! Ohne Arbeiter nur 30% Ertrag.',c:'bad'})
} else if (t === 'settlement') {
if (onRiver) return
if (cur !== 'meadow' && cur !== 'field') return
if (budget < 10) return
land[gr][gc] = 'settlement'; tilePop[gr][gc] = 0; tileCap[gr][gc] = 8; budget -= 10
const d = distToRiver(gr, gc)
if (d < 2) eventLog.push({t:'🏘️ Siedlung gebaut — sehr nah am Fluss! Hochwassergefahr! Deich empfohlen.',c:'bad'})
else if (d < 4) eventLog.push({t:'🏘️ Siedlung gebaut — gute Lage. Bewohner ziehen bald ein, wenn Nahrung da ist.',c:'good'})
else eventLog.push({t:'🏘️ Siedlung gebaut — sicher, aber weit weg. Felder in der Nähe anlegen!',c:''})
} else if (t === 'forest') {
if (onRiver) return
if (cur !== 'meadow') return
if (budget < 5) return
land[gr][gc] = 'forest'; budget -= 5
eventLog.push({t:'🌳 Wald gepflanzt — schützt vor Erosion und speichert Grundwasser.',c:'good'})
} else if (t === 'demolish') {
// Begradigung abreissen: auf Fluss klicken
if (onRiver && riverEng[gr] > 0) {
if (budget < 2) return
riverEng[gr] = 0 // Befestigung entfernt → Fluss wandert dort wieder frei
budget -= 2
eventLog.push({t:'🗑️ Begradigung entfernt (Zeile '+( gr+1)+')',c:''})
renderUI(); return
}
if (!['field','settlement','levee','ruin','dead_tree','forest'].includes(cur)) return
if (budget < 2) return
land[gr][gc] = 'meadow'; budget -= 2
}
renderUI()
}
// === CANVAS ===
const $cv = document.getElementById('cv'), ctx = $cv.getContext('2d')
let W=0, H=0, tw=0, th=0, animT=0
function resize() {
const r=$cv.parentElement.getBoundingClientRect(), dpr=devicePixelRatio||1
$cv.width=r.width*dpr;$cv.height=r.height*dpr;ctx.setTransform(dpr,0,0,dpr,0,0)
W=r.width;H=r.height;tw=W/COLS;th=H/ROWS
}
function draw() {
animT += 0.012
const s = Math.min(tw, th) * 0.3
// Background
ctx.fillStyle='#c8d8b0'; ctx.fillRect(0,0,W,H)
// === TILES ===
for (let r=0;r<ROWS;r++) for (let c=0;c<COLS;c++) {
const x=c*tw, y=r*th, tile=land[r][c]
const dist=distToRiver(r,c)
const fi=floodIntensity[r]?.[c]||0
const moisture=Math.max(0,1-dist/5) * 0.2 // permanente Feuchtigkeit nahe Fluss
// Grundfarbe
let bR=155,bG=185,bB=120 // meadow
if(tile==='forest'){bR=55;bG=115;bB=45}
if(tile==='field'){bR=185;bG=170;bB=75}
if(tile==='settlement'){bR=175;bG=150;bB=115}
if(tile==='levee'){bR=135;bG=110;bB=80}
if(tile==='ruin'){bR=125;bG=110;bB=95}
if(tile==='dead_tree'){bR=105;bG=125;bB=75}
// Feuchtigkeit + Hochwasser → Blau-Shift
const blue = Math.min(1, moisture + fi * 0.7)
const fR=bR*(1-blue)+65*blue|0
const fG=bG*(1-blue*0.4)+135*blue*0.4|0
const fB=bB*(1-blue)+185*blue|0
ctx.fillStyle=`rgb(${fR},${fG},${fB})`
ctx.fillRect(x,y,tw+0.5,th+0.5)
// Tile-Objekte
const cx=x+tw/2, cy=y+th/2
if(tile==='forest'){
ctx.fillStyle='#4a3020';ctx.fillRect(cx-s*0.1,cy-s*0.2,s*0.2,s*0.5)
ctx.fillStyle=r<ROWS*0.3?'#1a5a2a':'#2a7a2a'
ctx.beginPath();ctx.arc(cx,cy-s*0.4,s*0.45,0,Math.PI*2);ctx.fill()
}
if(tile==='settlement'){
// 3x3 Raster: Personen aussen, Haus-Emoji in der Mitte
// Personen-Emojis je nach Gesundheit (Feuchtigkeit des Hauses)
const pop=tilePop[r]?.[c]||0
const efs=Math.max(6,Math.min(12,tw*0.28))
ctx.font=`${efs}px serif`;ctx.textAlign='center';ctx.textBaseline='middle'
const gx=tw*0.32, gy=th*0.32
const healthy=['👩','👨','👧','👦','👩‍🦱','👨‍🦰','👱‍♀️','🧑']
const sick=['😰','🤒','🤢','😷','🤒','😰','🤢','😷']
for(let gr_=0;gr_<3;gr_++)for(let gc_=0;gc_<3;gc_++){
const idx=gr_*3+gc_
if(idx===4){ctx.fillText('🏘️',cx,cy)}
else{
const slotIdx=idx>4?idx-1:idx
if(slotIdx<pop){
// Gesund, leicht krank, schwer krank je nach Feuchtigkeit
let emoji
if(fi>0.35) emoji=sick[slotIdx%8] // schwer krank
else if(fi>0.15) emoji=(slotIdx%2===0)?sick[slotIdx%8]:healthy[slotIdx%8] // manche krank
else emoji=healthy[slotIdx%8] // alle gesund
ctx.fillText(emoji,cx+(gc_-1)*gx,cy+(gr_-1)*gy)
}
}
}
ctx.textBaseline='alphabetic'
}
if(tile==='field'){
// 3x3 Emoji-Raster: Weizen aussen, Status-Emoji in der Mitte
const yi=tileYield[r]?.[c]||0
const dist_=distToRiver(r,c)
let dryPen=0; for(let ii=Math.max(0,r-1);ii<=Math.min(ROWS-1,r+1);ii++){if(riverEng[ii]>0)dryPen=Math.max(dryPen,riverEng[ii]*0.25)}
const moist=Math.max(0,(1-Math.abs(dist_-2.5)/3)-dryPen)
// Status: 💧=nass, 👍=gut, 🥵=trocken
let status; if(fi>0.25) status='💧'; else if(moist>0.4) status='👍'; else status='🥵'
// 8 Positionen um die Mitte: Weizen oder Wasser
// Bei Ueberschwemmung ersetzen Wasser-Emojis den Weizen von unten
const waterSlots = fi > 0.15 ? Math.min(8, Math.round(fi * 12)) : 0
const wheatSlots = Math.min(8, yi) - waterSlots
const grid3 = [] // 9 Positionen: 0-8, Mitte=4
for(let p=0;p<9;p++){
if(p===4){grid3[p]=status; continue}
const slotIdx=p>4?p-1:p // 0-7 fuer die 8 Aussenpositionen
if(slotIdx<Math.max(0,wheatSlots)) grid3[p]='🌾'
else if(slotIdx<Math.max(0,wheatSlots)+waterSlots) grid3[p]='💧'
else grid3[p]=''
}
const efs=Math.max(6,Math.min(12,tw*0.28))
ctx.font=`${efs}px serif`;ctx.textAlign='center';ctx.textBaseline='middle'
const gx=tw*0.32, gy=th*0.32
for(let gr_=0;gr_<3;gr_++)for(let gc_=0;gc_<3;gc_++){
const idx=gr_*3+gc_
if(grid3[idx]){ctx.fillText(grid3[idx],cx+(gc_-1)*gx,cy+(gr_-1)*gy)}
}
ctx.textBaseline='alphabetic'
}
if(tile==='levee'){
// Deich — wird schmaler bei Erosion (hohe flood intensity)
const w=s*0.8*(1-fi*0.5)
ctx.fillStyle=fi>0.3?'rgba(140,115,85,0.5)':'rgba(140,115,85,0.9)'
ctx.fillRect(cx-w,cy-s*0.1,w*2,s*0.25)
}
if(tile==='ruin'){
ctx.fillStyle='rgba(100,85,70,0.5)';ctx.fillRect(cx-s*0.3,cy-s*0.15,s*0.6,s*0.3)
}
if(tile==='dead_tree'){
ctx.strokeStyle='#2a2a2a';ctx.lineWidth=Math.max(0.5,s*0.1)
ctx.beginPath();ctx.moveTo(cx,cy+s*0.2);ctx.lineTo(cx+s*0.05,cy-s*0.3)
ctx.moveTo(cx+s*0.03,cy-s*0.15);ctx.lineTo(cx-s*0.2,cy-s*0.4)
ctx.stroke()
}
}
// Gitter (dezent)
ctx.strokeStyle='rgba(0,0,0,0.04)';ctx.lineWidth=0.3
for(let r=0;r<=ROWS;r++){ctx.beginPath();ctx.moveTo(0,r*th);ctx.lineTo(W,r*th);ctx.stroke()}
for(let c=0;c<=COLS;c++){ctx.beginPath();ctx.moveTo(c*tw,0);ctx.lineTo(c*tw,H);ctx.stroke()}
// === FLUSS — fliessender Verlauf aus interpolierten Kreisen ===
// Smooth-Animation: riverColSmooth wandert langsam zu riverCol
for (let i = 0; i < ROWS; i++) {
riverColSmooth[i] += (riverCol[i] - riverColSmooth[i]) * 0.06
}
// Virtuelle Punkte oben und unten (damit der Fluss nicht im Nichts beginnt)
const pts = [] // {x (pixel), y (pixel), rad (pixel), eng}
// Virtueller Punkt oberhalb
pts.push({
x: riverColSmooth[0] * tw + tw/2,
y: -th,
rad: riverRadius[0] * tw * 0.45,
eng: riverEng[0]
})
// Alle echten Punkte
for (let i = 0; i < ROWS; i++) {
pts.push({
x: riverColSmooth[i] * tw + tw/2,
y: i * th + th/2,
rad: riverRadius[i] * tw * 0.45,
eng: riverEng[i]
})
}
// Virtueller Punkt unterhalb
pts.push({
x: riverColSmooth[ROWS-1] * tw + tw/2,
y: H + th,
rad: riverRadius[ROWS-1] * tw * 0.45,
eng: riverEng[ROWS-1]
})
// Fluss zeichnen: Kreise entlang der Verbindungen, Radius interpoliert
const totalPts = pts.length
for (let i = 0; i < totalPts - 1; i++) {
const p0 = pts[i], p1 = pts[i+1]
const steps = 12
for (let s = 0; s <= steps; s++) {
const t = s / steps
const px = p0.x + (p1.x - p0.x) * t
const py = p0.y + (p1.y - p0.y) * t
const pr = p0.rad + (p1.rad - p0.rad) * t // Radius interpoliert
const rr = pr + Math.sin(animT * 1.8 + py * 0.01) * pr * 0.06 // leichtes Pulsieren
// Wasser
ctx.fillStyle = 'rgba(50,118,172,0.88)'
ctx.beginPath(); ctx.arc(px, py, rr, 0, Math.PI * 2); ctx.fill()
}
}
// Schimmer/Stroemung ueber den ganzen Fluss
ctx.strokeStyle = `rgba(255,255,255,${0.06 + Math.sin(animT * 2) * 0.03})`; ctx.lineWidth = 0.8
for (let k = 0; k < 8; k++) {
const t = (k / 8 + animT * 0.02) % 1
const idx = t * (totalPts - 1)
const i = Math.floor(idx), frac = idx - i
if (i >= totalPts - 1) continue
const px = pts[i].x + (pts[i+1].x - pts[i].x) * frac
const py = pts[i].y + (pts[i+1].y - pts[i].y) * frac
const pr = pts[i].rad + (pts[i+1].rad - pts[i].rad) * frac
ctx.beginPath(); ctx.moveTo(px - pr * 0.4, py); ctx.lineTo(px + pr * 0.4, py + 1); ctx.stroke()
}
// Uferbefestigung bei begradigten Segmenten
for (let i = 1; i < totalPts - 1; i++) {
const p = pts[i]
const eng = p.eng
if (eng > 0) {
const engColors = ['','rgba(130,100,50,0.5)','rgba(110,110,110,0.6)','rgba(160,160,160,0.7)']
ctx.strokeStyle = engColors[Math.min(3, eng)]
ctx.lineWidth = 1.5 + eng * 1.2
const segH = th * 0.5
ctx.beginPath(); ctx.moveTo(p.x - p.rad - 2, p.y - segH); ctx.lineTo(p.x - p.rad - 2, p.y + segH); ctx.stroke()
ctx.beginPath(); ctx.moveTo(p.x + p.rad + 2, p.y - segH); ctx.lineTo(p.x + p.rad + 2, p.y + segH); ctx.stroke()
}
}
// === WOLKEN ===
for(let i=0;i<3;i++){
const cx=((animT*(10+i*4)+i*250)%(W+120))-60
const cy=10+i*18+Math.sin(animT*0.3+i)*4
const isRain=weather.f>=1.5&&i<2
ctx.fillStyle=isRain?'rgba(90,90,110,0.3)':'rgba(255,255,255,0.35)'
ctx.beginPath();ctx.ellipse(cx,cy,22,8,0,0,Math.PI*2);ctx.fill()
ctx.beginPath();ctx.ellipse(cx-10,cy+2,16,7,0,0,Math.PI*2);ctx.fill()
ctx.beginPath();ctx.ellipse(cx+12,cy+1,18,7,0,0,Math.PI*2);ctx.fill()
if(isRain){ctx.strokeStyle='rgba(80,130,180,0.2)';ctx.lineWidth=0.5
for(let j=0;j<4;j++){const dx=cx-8+j*5;ctx.beginPath();ctx.moveTo(dx,cy+8);ctx.lineTo(dx-1,cy+14+Math.random()*3);ctx.stroke()}}
}
// Floating emojis
const now=performance.now()
for(let i=floats.length-1;i>=0;i--){
const f=floats[i],age=(now-f.t)/1000
if(age>3){floats.splice(i,1);continue}
f.y-=0.0004
ctx.globalAlpha=Math.max(0,1-age/3)
ctx.font=`${12+age*3}px serif`;ctx.textAlign='center'
ctx.fillText(f.e,f.x*W,f.y*H)
ctx.globalAlpha=1
}
}
// === RENDER UI ===
function renderUI(){
let inc=0,pop=0,food=0,sett=0,fld=0,for_=0,lev=0,ruin=0
for(let r=0;r<ROWS;r++)for(let c=0;c<COLS;c++){
const t=land[r][c];if(t==='settlement'){sett++;pop+=tilePop[r][c]}
if(t==='field'){fld++;food+=tileYield[r][c];inc+=tileYield[r][c]*0.5}
if(t==='forest')for_++;if(t==='levee')lev++;if(t==='ruin')ruin++
if(t==='settlement')inc+=tilePop[r][c]*0.8
}
document.getElementById('h-bud').textContent=budget
document.getElementById('h-inc').textContent=`+${Math.round(inc)}/J`
document.getElementById('h-yr').textContent=`${year}/${MAX_YEARS}`
document.getElementById('h-wx').textContent=`${weather.e} ${weather.n}`
const avgEng=riverEng.reduce((s,v)=>s+v,0)/ROWS
const floodTotal=floodIntensity.flat().reduce((s,v)=>s+v,0)/(ROWS*COLS)
const clamp=v=>Math.min(100,Math.max(0,Math.round(v)))
const ps=[
{n:`Bevölkerung (${pop})`,i:'👥',v:pop,abs:true}, // absolut, nicht 0-100
{n:'Nahrung',i:'🌾',v:clamp(food*1.5-(weather.f<0.3?20:0))},
{n:'Biodiversität',i:'🦎',v:clamp(for_*4-avgEng*30-(sett+fld)*1.5)},
{n:'Hochwasserschutz',i:'🛡️',v:clamp(15+lev*6+avgEng*8-floodTotal*80)},
{n:'Wirtschaft',i:'💰',v:clamp(pop*3+fld*2-ruin*5)},
]
document.getElementById('params').innerHTML=ps.map(p=>{
const col=p.v<30?'var(--coral)':p.v>55?'var(--moss)':'var(--sand)'
return `<div class="param"><div class="param-i">${p.i}</div><div class="param-inf"><div class="param-n">${p.n}</div><div class="param-bar"><div class="param-bar-f" style="width:${p.v}%;background:${col}"></div></div></div><div class="param-v" style="color:${col}">${p.v}</div></div>`
}).join('')
document.getElementById('log').innerHTML=eventLog.slice(-10).reverse().map(e=>`<div class="log ${e.c}">${e.t}</div>`).join('')
// Wenn selektiertes Tool nicht mehr leistbar → abwaehlen
if(selectedTool){const st=TOOLS.find(t=>t.id===selectedTool);if(st&&budget<st.cost)selectedTool=null}
document.getElementById('tools').innerHTML=TOOLS.map(t=>{
const af=budget>=t.cost;return `<div class="tool ${selectedTool===t.id&&af?'on':''} ${!af?'off':''}" data-t="${t.id}"><span class="tool-e">${t.e}</span><div class="tool-inf"><div class="tool-nm">${t.nm}</div><div class="tool-ds">${t.ds}</div></div><span class="tool-c">💰${t.cost}</span></div>`
}).join('')
document.querySelectorAll('.tool').forEach(b=>b.addEventListener('click',()=>{selectedTool=selectedTool===b.dataset.t?null:b.dataset.t;renderUI()}))
// === GRAPH ===
drawGraph()
}
function drawGraph(){
const gc=document.getElementById('graph')
if(!gc||history.length<2)return
const gctx=gc.getContext('2d')
const rect=gc.parentElement.getBoundingClientRect()
const dpr=devicePixelRatio||1
gc.width=rect.width*dpr;gc.height=90*dpr;gctx.setTransform(dpr,0,0,dpr,0,0)
const gW=rect.width,gH=90
gctx.clearRect(0,0,gW,gH)
// Hintergrund-Zonen (Toleranzen)
gctx.fillStyle='rgba(180,60,50,0.06)';gctx.fillRect(0,gH*0.75,gW,gH*0.25) // Gefahrenzone unten
gctx.fillStyle='rgba(90,140,90,0.06)';gctx.fillRect(0,0,gW,gH*0.35) // Gute Zone oben
gctx.fillStyle='rgba(200,180,80,0.06)';gctx.fillRect(0,gH*0.35,gW,gH*0.4) // Mittelzone
// Trennlinien
gctx.strokeStyle='rgba(0,0,0,0.06)';gctx.lineWidth=0.5;gctx.setLineDash([3,3])
gctx.beginPath();gctx.moveTo(0,gH*0.35);gctx.lineTo(gW,gH*0.35);gctx.stroke()
gctx.beginPath();gctx.moveTo(0,gH*0.75);gctx.lineTo(gW,gH*0.75);gctx.stroke()
gctx.setLineDash([])
// Labels
gctx.font='7px Inter,sans-serif';gctx.fillStyle='rgba(0,0,0,0.2)';gctx.textAlign='right'
gctx.fillText('gut',gW-3,gH*0.2);gctx.fillText('kritisch',gW-3,gH*0.88)
const lines=[
{key:'pop',color:'#6a6aaa',label:'👥'},
{key:'food',color:'#8a9a30',label:'🌾'},
{key:'bio',color:'#3a8a3a',label:'🦎'},
{key:'safety',color:'#4a7c8a',label:'🛡️'},
{key:'economy',color:'#c4a35a',label:'💰'},
]
// Auto-scale: finde max ueber alle Werte
let maxVal=100
for(const h of history)for(const l of lines){const v=h[l.key]||0;if(v>maxVal)maxVal=v}
maxVal=Math.max(100,maxVal*1.1)
const pad=2,plotW=gW-pad*2,plotH=gH-pad*2
for(const line of lines){
gctx.strokeStyle=line.color;gctx.lineWidth=1.2;gctx.beginPath()
history.forEach((h,i)=>{
const x=pad+(i/(Math.max(1,MAX_YEARS-1)))*plotW
const y=pad+plotH-(((h[line.key]||0)/maxVal)*plotH)
i===0?gctx.moveTo(x,y):gctx.lineTo(x,y)
})
gctx.stroke()
// Label am Ende
if(history.length>0){
const last=history[history.length-1]
const lx=pad+((history.length-1)/(Math.max(1,MAX_YEARS-1)))*plotW
const ly=pad+plotH-(((last[line.key]||0)/maxVal)*plotH)
gctx.font='8px serif';gctx.textAlign='left';gctx.fillStyle=line.color
gctx.fillText(line.label,lx+3,ly+3)
}
}
}
// === EVENTS ===
const $cv2=$cv
$cv2.addEventListener('click',e=>{
const r=$cv2.getBoundingClientRect()
const gc=Math.floor((e.clientX-r.left)/tw), gr=Math.floor((e.clientY-r.top)/th)
applyAt(gr,gc)
})
$cv2.addEventListener('mousemove',e=>{
const r=$cv2.getBoundingClientRect()
const gc=Math.floor((e.clientX-r.left)/tw), gr=Math.floor((e.clientY-r.top)/th)
if(gr>=0&&gr<ROWS&&gc>=0&&gc<COLS){
const t=land[gr][gc],dist=distToRiver(gr,gc).toFixed(1)
const onR=isRiverTile(gr,gc)
let info=onR?`🌊 Fluss (Befestigung: ${riverEng[gr]})`:
{meadow:'🌱 Wiese',forest:'🌳 Wald',field:`🌾 Feld (Ertrag: ${tileYield[gr]?.[gc]||0})`,
settlement:`🏠 Siedlung (${tilePop[gr]?.[gc]||0}/8)`,levee:'🧱 Deich',ruin:'🏚️ Ruine',dead_tree:'🪵 Toter Baum'}[t]||t
info+=`<br>Flussabstand: ${dist}`
document.getElementById('info').innerHTML=info
}
})
document.querySelectorAll('.spd button').forEach(b=>b.addEventListener('click',()=>{
speed=parseInt(b.dataset.s);document.querySelectorAll('.spd button').forEach(x=>x.classList.remove('on'));b.classList.add('on')
}))
function showEnd(){
document.getElementById('end-t').textContent='100 Jahre sind um!'
let p=0;for(let r=0;r<ROWS;r++)for(let c=0;c<COLS;c++)p+=tilePop[r][c]
document.getElementById('end-p').textContent=`💰${budget} | 👥${p} Bewohner | 🏠${land.flat().filter(t=>t==='settlement').length} Siedlungen`
document.getElementById('ov-end').classList.remove('hidden')
}
document.getElementById('btn-go').addEventListener('click',()=>{document.getElementById('ov-intro').classList.add('hidden');renderUI()})
document.getElementById('btn-again').addEventListener('click',()=>{document.getElementById('ov-end').classList.add('hidden');initGame();renderUI()})
document.getElementById('btn-reset').addEventListener('click',()=>{if(confirm('Neu?')){initGame();renderUI()}})
// === GAME LOOP ===
let lastT=0
function loop(ts){if(!lastT)lastT=ts;const dt=ts-lastT;lastT=ts
if(speed>0&&!gameOver){tickAccum+=dt*speed;while(tickAccum>=MS_PER_TICK){tickAccum-=MS_PER_TICK;tick()}}
draw()
requestAnimationFrame(loop)}
initGame();resize();window.addEventListener('resize',resize);renderUI();draw();requestAnimationFrame(loop)
</script>
</body>
</html>
File diff suppressed because it is too large Load Diff
@@ -1,522 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Klimawächter</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="assets/fonts/inter.css">
<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.5; }
.nav { padding:.6rem 1.2rem; display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid rgba(0,0,0,.05); background:var(--white); }
.nav-brand { display:flex; align-items:center; gap:.5rem; font-weight:800; font-size:1rem; color:var(--fjord); text-decoration:none; }
.nav-brand img { width:28px; height:28px; border-radius:6px; }
.nav-actions { display:flex; gap:.4rem; }
.nav-btn { padding:.4rem .8rem; border:1px solid rgba(0,0,0,.08); border-radius:8px; background:var(--white); color:var(--text2); font-size:.78rem; font-weight:600; cursor:pointer; text-decoration:none; }
.nav-btn:hover { background:var(--fjord-l); border-color:var(--fjord); color:var(--fjord); }
/* === MAIN LAYOUT === */
.game-layout { display:grid; grid-template-columns:280px 1fr 280px; gap:.8rem; padding:.8rem; max-width:1400px; margin:0 auto; align-items:start; }
.panel { background:var(--white); border-radius:12px; border:1px solid rgba(0,0,0,.05); padding:.9rem; box-shadow:0 2px 8px rgba(0,0,0,.03); }
.panel-h { font-size:.66rem; font-weight:700; color:var(--fjord); text-transform:uppercase; letter-spacing:.06em; margin-bottom:.5rem; }
/* === LEFT: Resources & Goals === */
.left { display:flex; flex-direction:column; gap:.8rem; }
.resource { display:flex; align-items:center; gap:.6rem; padding:.4rem .2rem; border-bottom:1px solid rgba(0,0,0,.04); }
.resource:last-child { border-bottom:none; }
.resource-icon { font-size:1.4rem; width:28px; text-align:center; }
.resource-info { flex:1; min-width:0; }
.resource-name { font-size:.7rem; color:var(--text3); font-weight:500; }
.resource-val { font-size:.95rem; font-weight:700; color:var(--text); }
.resource-trend { font-size:.65rem; padding:1px 5px; border-radius:4px; font-weight:600; }
.trend-up { background:var(--moss-l); color:var(--moss); }
.trend-down { background:var(--coral-l); color:var(--coral); }
.goals .goal { padding:.4rem 0; border-bottom:1px solid rgba(0,0,0,.04); }
.goals .goal:last-child { border:0; }
.goal-row { display:flex; align-items:center; gap:.4rem; font-size:.78rem; }
.goal-check { width:14px; height:14px; border:1.5px solid var(--text3); border-radius:3px; display:flex; align-items:center; justify-content:center; font-size:.6rem; flex-shrink:0; }
.goal-check.done { background:var(--moss); border-color:var(--moss); color:#fff; }
.goal-bar { height:3px; background:#e8e5dc; border-radius:2px; margin-top:.3rem; overflow:hidden; }
.goal-bar-fill { height:100%; background:var(--moss); transition:width .3s; }
/* === CENTER: Game Canvas + Controls === */
.center { display:flex; flex-direction:column; gap:.6rem; }
.canvas-wrap { background:var(--white); border-radius:14px; border:1px solid rgba(0,0,0,.05); overflow:visible; box-shadow:0 4px 16px rgba(0,0,0,.05); position:relative; min-height:460px; }
/* Tutorial Overlay */
.tutorial-overlay { position:absolute; inset:0; background:rgba(15,30,40,.85); backdrop-filter:blur(8px); display:flex; align-items:center; justify-content:center; z-index:10; padding:1.5rem; }
.tutorial-card { background:var(--white); border-radius:16px; padding:1.5rem 1.8rem; max-width:480px; box-shadow:0 20px 60px rgba(0,0,0,.3); }
.tutorial-card h3 { font-size:1.2rem; font-weight:800; margin-bottom:.6rem; color:var(--fjord); }
.tutorial-card p { font-size:.88rem; color:var(--text2); white-space:pre-line; margin-bottom:1rem; }
.tutorial-card .progress-dots { display:flex; gap:.3rem; justify-content:center; margin:.8rem 0; }
.dot { width:8px; height:8px; border-radius:50%; background:#dadad0; }
.dot.active { background:var(--fjord); }
.tut-btn { width:100%; padding:.7rem; background:var(--fjord); color:#fff; border:none; border-radius:10px; font-weight:700; font-size:.9rem; cursor:pointer; }
.tut-btn:hover { background:var(--fjord-d); }
/* Speed controls */
.speed-bar { display:flex; gap:.3rem; padding:.5rem; background:var(--white); border-radius:10px; border:1px solid rgba(0,0,0,.05); }
.speed-btn { flex:1; padding:.5rem; border:none; background:transparent; color:var(--text2); font-size:.8rem; font-weight:600; cursor:pointer; border-radius:6px; }
.speed-btn:hover { background:#f0eeea; }
.speed-btn.active { background:var(--fjord); color:#fff; }
/* Graphs */
.graphs { display:grid; grid-template-columns:1fr 1fr; gap:.5rem; margin-top:.4rem; }
.graph-card { background:var(--white); border-radius:10px; border:1px solid rgba(0,0,0,.05); padding:.5rem .6rem .3rem; }
.graph-title { font-size:.65rem; color:var(--text3); font-weight:600; text-transform:uppercase; letter-spacing:.06em; margin-bottom:.2rem; }
.graph-svg { width:100%; height:55px; display:block; }
/* === RIGHT: Measures Shop & Events === */
.right { display:flex; flex-direction:column; gap:.8rem; max-height:50vh; overflow-y:auto; }
.measure-card { display:flex; gap:.6rem; padding:.6rem; border-radius:10px; border:1px solid rgba(0,0,0,.06); margin-bottom:.4rem; cursor:pointer; transition:all .2s; background:var(--white); }
.measure-card:hover { border-color:var(--fjord); background:var(--fjord-l); }
.measure-card.disabled { opacity:.5; cursor:not-allowed; }
.measure-card.disabled:hover { border-color:rgba(0,0,0,.06); background:var(--white); }
.measure-icon { font-size:1.5rem; width:32px; text-align:center; }
.measure-info { flex:1; min-width:0; }
.measure-name { font-size:.8rem; font-weight:700; }
.measure-desc { font-size:.66rem; color:var(--text3); line-height:1.3; }
.measure-stats { display:flex; gap:.3rem; flex-wrap:wrap; margin-top:.2rem; }
.measure-stat { font-size:.6rem; padding:1px 5px; border-radius:4px; background:#f0eeea; color:var(--text3); font-weight:600; }
.measure-cost { background:var(--sand-l); color:var(--sand); }
.measure-co2 { background:var(--moss-l); color:var(--moss); }
.measure-protect { background:var(--fjord-l); color:var(--fjord); }
.measure-count { font-size:.62rem; padding:1px 5px; border-radius:4px; background:var(--fjord); color:#fff; font-weight:700; }
.events-list { max-height:160px; overflow-y:auto; }
.event { padding:.4rem .5rem; border-radius:8px; margin-bottom:.3rem; font-size:.74rem; line-height:1.3; }
.event-info { background:#f0eeea; color:var(--text2); }
.event-success { background:var(--moss-l); color:var(--moss); }
.event-warning { background:var(--sand-l); color:var(--sand); }
.event-danger { background:var(--coral-l); color:var(--danger); }
/* === END SCREEN === */
.end-screen { position:fixed; inset:0; background:rgba(15,30,40,.9); backdrop-filter:blur(10px); display:flex; align-items:center; justify-content:center; z-index:100; padding:2rem; }
.end-card { background:var(--white); border-radius:20px; padding:2rem 2.5rem; max-width:500px; text-align:center; box-shadow:0 30px 80px rgba(0,0,0,.4); }
.end-icon { font-size:4rem; margin-bottom:.5rem; }
.end-card h2 { font-size:1.8rem; font-weight:900; letter-spacing:-.02em; margin-bottom:.3rem; }
.end-card .end-summary { color:var(--text2); margin-bottom:1rem; }
.end-stats { display:grid; grid-template-columns:1fr 1fr; gap:.8rem; margin:1rem 0; }
.end-stat { background:#f7f6f3; border-radius:10px; padding:.8rem; }
.end-stat-val { font-size:1.4rem; font-weight:800; color:var(--fjord); }
.end-stat-lbl { font-size:.7rem; color:var(--text3); text-transform:uppercase; }
/* RESPONSIVE */
@media (max-width: 1100px) {
.game-layout { grid-template-columns:1fr; }
.left, .right { order:2; }
}
</style>
</head>
<body>
<nav class="nav">
<a href="index.html" class="nav-brand"><img src="assets/img/logo.png" alt="">GeoGraSim · Klimawächter</a>
<div class="nav-actions">
<button class="nav-btn" id="btn-save">💾 Speichern</button>
<button class="nav-btn" id="btn-load">📂 Laden</button>
<button class="nav-btn" id="btn-finish">⏹ Beenden</button>
<button class="nav-btn" id="btn-reset" title="Stand löschen und neu starten">🔄 Reset</button>
<a href="index.html" class="nav-btn">← Zurück</a>
</div>
</nav>
<div class="game-layout">
<!-- LEFT: Resources, Goals -->
<aside class="left">
<div class="panel">
<div class="panel-h">📊 Status</div>
<div id="resources"></div>
</div>
<div class="panel goals">
<div class="panel-h">🎯 Ziele</div>
<div id="goals"></div>
</div>
</aside>
<!-- CENTER: Canvas + Controls + Graphs -->
<main class="center">
<div class="canvas-wrap" id="canvas-wrap">
<div class="tutorial-overlay" id="tutorial">
<div class="tutorial-card">
<h3 id="tut-title"></h3>
<p id="tut-text"></p>
<div class="progress-dots" id="tut-dots"></div>
<button class="tut-btn" id="tut-next">Weiter →</button>
</div>
</div>
</div>
<div class="speed-bar">
<button class="speed-btn" data-speed="0"></button>
<button class="speed-btn active" data-speed="1">▶ Normal</button>
<button class="speed-btn" data-speed="2">⏩ Schnell</button>
<button class="speed-btn" data-speed="4">⏭ Sehr schnell</button>
</div>
<div class="graphs">
<div class="graph-card">
<div class="graph-title">🌫 CO₂ über Zeit</div>
<svg class="graph-svg" id="graph-co2"></svg>
</div>
<div class="graph-card">
<div class="graph-title">🌡 Temperatur über Zeit</div>
<svg class="graph-svg" id="graph-temp"></svg>
</div>
<div class="graph-card">
<div class="graph-title">💰 Budget über Zeit</div>
<svg class="graph-svg" id="graph-budget"></svg>
</div>
<div class="graph-card">
<div class="graph-title">🌊 Meeresspiegel über Zeit</div>
<svg class="graph-svg" id="graph-sea"></svg>
</div>
</div>
</main>
<!-- RIGHT: Measures Shop, Events -->
<aside class="right">
<div class="panel">
<div class="panel-h">🏗 Maßnahmen kaufen</div>
<div id="measures"></div>
</div>
<div class="panel">
<div class="panel-h">📰 Ereignisse</div>
<div class="events-list" id="events"></div>
</div>
</aside>
</div>
<!-- End screen template -->
<div id="end-screen-host"></div>
<script type="module">
import { KlimawaechterGame, MEASURES } from './src/sims/sim-05-treibhaus/game.ts'
import { KlimawaechterRenderer } from './src/sims/sim-05-treibhaus/game-renderer.ts'
const game = new KlimawaechterGame()
let renderer = null
let endShown = false
// === ELEMENTS ===
const tutorialEl = document.getElementById('tutorial')
const tutTitle = document.getElementById('tut-title')
const tutText = document.getElementById('tut-text')
const tutDots = document.getElementById('tut-dots')
const tutNext = document.getElementById('tut-next')
const resourcesEl = document.getElementById('resources')
const goalsEl = document.getElementById('goals')
const measuresEl = document.getElementById('measures')
const eventsEl = document.getElementById('events')
const canvasWrap = document.getElementById('canvas-wrap')
// === RENDER MEASURES SHOP ===
function renderMeasures() {
const budget = game.getResource('budget')
measuresEl.innerHTML = MEASURES.map(m => {
const count = game.getMeasureCount(m.id)
const canAfford = budget >= m.cost
return `
<div class="measure-card ${canAfford ? '' : 'disabled'}" data-id="${m.id}">
<div class="measure-icon">${m.emoji}</div>
<div class="measure-info">
<div style="display:flex;justify-content:space-between;align-items:center">
<div class="measure-name">${m.name}</div>
${count > 0 ? `<span class="measure-count">×${count}</span>` : ''}
</div>
<div class="measure-desc">${m.description}</div>
<div class="measure-stats">
<span class="measure-stat measure-cost">💰 ${m.cost} €</span>
${m.co2Reduction > 0 ? `<span class="measure-stat measure-co2">${m.co2Reduction} CO₂/J</span>` : ''}
${m.protection > 0 ? `<span class="measure-stat measure-protect">🛡 +${m.protection} cm</span>` : ''}
<span class="measure-stat">⚙ ${m.upkeep} €/J</span>
</div>
</div>
</div>
`
}).join('')
measuresEl.querySelectorAll('.measure-card').forEach(el => {
el.addEventListener('click', () => {
if (el.classList.contains('disabled')) return
const id = el.dataset.id
game.buyMeasure(id)
})
})
}
// === RENDER RESOURCES ===
function renderResources() {
const resources = game.getResourcesArray()
resourcesEl.innerHTML = resources.map(r => `
<div class="resource">
<div class="resource-icon">${r.icon}</div>
<div class="resource-info">
<div class="resource-name">${r.name}</div>
<div class="resource-val">${r.format ? r.format(r.current) : r.current}</div>
</div>
</div>
`).join('')
}
// === RENDER GOALS ===
function renderGoals() {
const snap = game.getSnapshot()
goalsEl.innerHTML = snap.goals.map((g, i) => {
const goal = game.goals?.[i] || { title: g.id, description: '' }
return `
<div class="goal">
<div class="goal-row">
<div class="goal-check ${g.achieved ? 'done' : ''}">${g.achieved ? '✓' : ''}</div>
<div>${goal.title || g.id}</div>
</div>
<div class="goal-bar"><div class="goal-bar-fill" style="width:${g.progress}%"></div></div>
</div>
`
}).join('')
}
// === RENDER EVENTS ===
function renderEvents() {
const events = game.getEvents(8)
if (events.length === 0) {
eventsEl.innerHTML = '<div style="font-size:.72rem;color:var(--text3);text-align:center;padding:.5rem">Noch keine Ereignisse</div>'
return
}
eventsEl.innerHTML = events.map(e => `
<div class="event event-${e.severity}">
<strong>Jahr ${e.tick}:</strong> ${e.text}
</div>
`).join('')
}
// === RENDER GRAPHS (volle Version mit Zonen, Referenzlinien, Animation) ===
const GRAPH_CFG = [
{id:'graph-co2', key:'co2', color:'#8a7868', unit:'ppm', label:'CO₂',
zones:[{min:280,max:350,color:'rgba(90,138,94,.12)',label:'Vorindustriell'},{min:350,max:450,color:'rgba(196,163,90,.1)'},{min:450,max:800,color:'rgba(192,122,107,.08)'}],
lines:[{y:420,label:'Heute',color:'#c4a35a',dash:true}]},
{id:'graph-temp', key:'temperature', color:'#c07a6b', unit:'°C', label:'Temperatur',
zones:[{min:14,max:16,color:'rgba(90,138,94,.12)',label:'Sicher'},{min:16,max:17,color:'rgba(196,163,90,.1)'},{min:17,max:22,color:'rgba(192,122,107,.08)'}],
lines:[{y:17,label:'Klimaziel',color:'#c07a6b',dash:true}]},
{id:'graph-budget', key:'budget', color:'#5a8a5e', unit:'Mrd', label:'Budget',
zones:[], lines:[{y:0,label:'',color:'#ccc',dash:true}]},
{id:'graph-sea', key:'sealevel', color:'#4a7c8a', unit:'cm', label:'Meeresspiegel',
zones:[{min:0,max:30,color:'rgba(90,138,94,.08)'},{min:30,max:100,color:'rgba(196,163,90,.08)'},{min:100,max:300,color:'rgba(192,122,107,.08)'}],
lines:[{y:50,label:'Kritisch',color:'#c07a6b',dash:true}]}
]
function renderGraphs() {
const snap = game.getSnapshot()
const tl = snap.timeline
if (tl.length === 0) return
GRAPH_CFG.forEach(cfg => {
const pts = tl.filter(e => e.values).map(e => ({x: e.tick, y: e.values[cfg.key] || 0}))
// Append live value
const live = snap.values?.[cfg.key]
if (live !== undefined) pts.push({x: snap.tick, y: live})
drawGraph(cfg, pts)
})
}
function niceFloor(v, step) { return Math.floor(v / step) * step }
function niceCeil(v, step) { return Math.ceil(v / step) * step }
function fmtTick(v) { return Math.abs(v) >= 1000 ? (v/1000).toFixed(1)+'k' : v >= 10 ? v.toFixed(0) : v.toFixed(1) }
function drawGraph(cfg, points) {
const svg = document.getElementById(cfg.id)
if (!svg) return
const W = svg.clientWidth || 200, H = 55
const pad = {l:28, r:6, t:4, b:12}
const gw = W - pad.l - pad.r, gh = H - pad.t - pad.b
svg.setAttribute('viewBox', `0 0 ${W} ${H}`)
if (points.length < 2) { svg.innerHTML = ''; return }
// Auto-scale Y
let allY = points.map(p => p.y)
let yMin = Math.min(...allY), yMax = Math.max(...allY)
const margin = (yMax - yMin) * 0.1 || 1
const step = yMax - yMin > 100 ? 50 : yMax - yMin > 10 ? 5 : 1
yMin = niceFloor(yMin - margin, step)
yMax = niceCeil(yMax + margin, step)
if (yMin === yMax) { yMin -= 1; yMax += 1 }
const maxX = Math.max(30, points[points.length - 1].x)
const px = p => pad.l + (p.x / maxX) * gw
const py = p => pad.t + gh - ((p.y - yMin) / (yMax - yMin)) * gh
let html = ''
// Zones
;(cfg.zones || []).forEach(z => {
const zy1 = pad.t + gh - ((Math.min(z.max, yMax) - yMin) / (yMax - yMin)) * gh
const zy2 = pad.t + gh - ((Math.max(z.min, yMin) - yMin) / (yMax - yMin)) * gh
html += `<rect x="${pad.l}" y="${zy1}" width="${gw}" height="${zy2-zy1}" fill="${z.color}" />`
})
// Reference lines
;(cfg.lines || []).forEach(ln => {
if (ln.y >= yMin && ln.y <= yMax) {
const ly = pad.t + gh - ((ln.y - yMin) / (yMax - yMin)) * gh
html += `<line x1="${pad.l}" y1="${ly}" x2="${W-pad.r}" y2="${ly}" stroke="${ln.color}" stroke-width=".7" ${ln.dash ? 'stroke-dasharray="3,2"' : ''} />`
if (ln.label) html += `<text x="${W-pad.r-1}" y="${ly-2}" text-anchor="end" font-size="5.5" fill="${ln.color}" opacity=".7">${ln.label}</text>`
}
})
// Y-axis ticks
for (let i = 0; i <= 3; i++) {
const val = yMin + (yMax - yMin) * (i / 3)
const ty = pad.t + gh - (i / 3) * gh
html += `<text x="${pad.l-2}" y="${ty+2.5}" text-anchor="end" font-size="5.5" fill="#aaa">${fmtTick(val)}</text>`
html += `<line x1="${pad.l}" y1="${ty}" x2="${W-pad.r}" y2="${ty}" stroke="#eee" stroke-width=".3" />`
}
// Data line
const path = points.map((p, i) => `${i===0?'M':'L'} ${px(p).toFixed(1)} ${Math.max(pad.t+1, Math.min(H-pad.b-1, py(p))).toFixed(1)}`).join(' ')
html += `<path d="${path}" fill="none" stroke="${cfg.color}" stroke-width="1.8" stroke-linejoin="round" stroke-linecap="round" />`
// Animated dot at latest point
const last = points[points.length - 1]
const lx = px(last), ly = Math.max(pad.t+1, Math.min(H-pad.b-1, py(last)))
html += `<circle cx="${lx}" cy="${ly}" r="2.5" fill="${cfg.color}"><animate attributeName="r" values="2.5;4;2.5" dur="1.5s" repeatCount="indefinite"/><animate attributeName="opacity" values="1;.5;1" dur="1.5s" repeatCount="indefinite"/></circle>`
// Value badge
html += `<text x="${W-pad.r}" y="${pad.t+7}" text-anchor="end" font-size="7" font-weight="700" fill="${cfg.color}">${last.y.toFixed(last.y > 50 ? 0 : 1)} ${cfg.unit}</text>`
svg.innerHTML = html
}
// === TUTORIAL ===
function renderTutorial() {
const step = game.getCurrentTutorialStep()
if (!step || game.getSnapshot().state !== 'tutorial') {
tutorialEl.style.display = 'none'
if (!renderer) {
renderer = new KlimawaechterRenderer(canvasWrap, game)
renderer.start()
}
return
}
tutorialEl.style.display = 'flex'
tutTitle.textContent = step.title
tutText.textContent = step.text
const totalSteps = 4
tutDots.innerHTML = ''
for (let i = 0; i < totalSteps; i++) {
const d = document.createElement('div')
d.className = 'dot' + (i === game.getSnapshot().tutorialStep ? ' active' : '')
tutDots.appendChild(d)
}
tutNext.textContent = game.getSnapshot().tutorialStep === totalSteps - 1 ? 'Simulation starten 🚀' : 'Weiter →'
}
tutNext.addEventListener('click', () => {
game.nextTutorialStep()
renderAll()
})
// === SPEED CONTROL ===
document.querySelectorAll('.speed-btn').forEach(btn => {
btn.addEventListener('click', () => {
const speed = parseInt(btn.dataset.speed)
game.setSpeed(speed)
document.querySelectorAll('.speed-btn').forEach(b => b.classList.remove('active'))
btn.classList.add('active')
})
})
// === SAVE / LOAD / FINISH ===
document.getElementById('btn-save').addEventListener('click', () => {
localStorage.setItem('klimawaechter-save', game.serialize())
alert('💾 Stand gespeichert')
})
document.getElementById('btn-load').addEventListener('click', () => {
const save = localStorage.getItem('klimawaechter-save')
if (!save) { alert('Kein Stand vorhanden'); return }
if (game.deserialize(save)) {
renderAll()
alert('📂 Stand geladen')
}
})
document.getElementById('btn-finish').addEventListener('click', () => {
game.finish()
showEndScreen()
})
// === END SCREEN ===
function showEndScreen() {
if (endShown) return
endShown = true
const snap = game.getSnapshot()
const won = snap.state === 'won'
const lost = snap.state === 'lost'
const icon = won ? '🏆' : lost ? '💔' : '🏁'
const title = won ? 'Du hast gewonnen!' : lost ? 'Simulation gescheitert' : 'Simulation beendet'
const summary = won
? 'Glückwunsch! Du hast deine Stadt bis zum Jahr 2100 erfolgreich durch die Klimakrise geführt.'
: lost
? snap.resources.budget < 0 ? 'Deine Stadt ist pleite gegangen.' : 'Der steigende Meeresspiegel hat zu viele Häuser zerstört.'
: `Du hast im Jahr ${2025 + snap.tick} beendet.`
const html = `
<div class="end-screen">
<div class="end-card">
<div class="end-icon">${icon}</div>
<h2>${title}</h2>
<p class="end-summary">${summary}</p>
<div class="end-stats">
<div class="end-stat"><div class="end-stat-val">${snap.tick}</div><div class="end-stat-lbl">Jahre (bis ${2025 + snap.tick})</div></div>
<div class="end-stat"><div class="end-stat-val">${Math.round(snap.resources.budget)} €</div><div class="end-stat-lbl">Budget übrig</div></div>
<div class="end-stat"><div class="end-stat-val">${snap.resources.temperature.toFixed(1)}°C</div><div class="end-stat-lbl">Endtemperatur</div></div>
<div class="end-stat"><div class="end-stat-val">${Math.round(snap.resources.flooded)}%</div><div class="end-stat-lbl">Überflutet</div></div>
</div>
<button class="tut-btn" onclick="location.reload()">🔄 Nochmal spielen</button>
</div>
</div>
`
document.getElementById('end-screen-host').innerHTML = html
}
// === MAIN RENDER ===
function renderAll() {
renderResources()
renderGoals()
renderMeasures()
renderEvents()
renderGraphs()
renderTutorial()
const snap = game.getSnapshot()
if ((snap.state === 'won' || snap.state === 'lost') && !endShown) {
setTimeout(showEndScreen, 800)
}
}
// Subscribe to game updates
game.subscribe(renderAll)
// Initial render
renderAll()
</script>
</body>
</html>
@@ -1,454 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Helikopter-Navigation</title>
<link rel="icon" type="image/png" href="favicon-96x96.png">
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.9.4/dist/leaflet.css">
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',system-ui,sans-serif;overflow:hidden;height:100vh;background:#e8e4d8}
#map{width:100%;height:100vh}
/* Aktive Basen: groß, farbig */
.heli-active{font-size:32px;text-align:center;line-height:1;filter:drop-shadow(0 2px 4px rgba(0,0,0,.4))}
.heli-active.oeamtc{filter:drop-shadow(0 2px 4px rgba(0,0,0,.3)) brightness(1.3) saturate(3) hue-rotate(-30deg) sepia(.3)}
.heli-active.ara{filter:drop-shadow(0 2px 4px rgba(0,0,0,.3)) hue-rotate(320deg) saturate(2)}
.heli-active.police{filter:drop-shadow(0 2px 4px rgba(0,0,0,.3)) hue-rotate(180deg) saturate(1.5) brightness(1.1)}
.heli-active.bh{filter:drop-shadow(0 2px 4px rgba(0,0,0,.3)) hue-rotate(90deg) saturate(2)}
/* Inaktive Basen: klein, deutlich sichtbar aber entsättigt */
.heli-inactive{font-size:18px;text-align:center;line-height:1;filter:drop-shadow(0 1px 3px rgba(0,0,0,.3)) grayscale(.7) brightness(.7) contrast(1.2)}
/* Labels/Pills */
.heli-pill{font-family:'Inter',system-ui,sans-serif;font-weight:600;font-size:11px;white-space:nowrap;padding:3px 8px;border-radius:5px;background:rgba(255,255,255,.92);box-shadow:0 1px 4px rgba(0,0,0,.15);line-height:1.3;max-width:180px}
.heli-pill .pill-name{font-weight:800;display:block}
.heli-pill .pill-org{font-size:8px;opacity:.7;display:block}
.heli-pill.oeamtc{border-left:4px solid #d4a017;color:#7a5f00}
.heli-pill.ara{border-left:4px solid #cc3333;color:#882222}
.heli-pill.police{border-left:4px solid #2255aa;color:#1a3a77}
.heli-pill.bh{border-left:4px solid #228833;color:#145522}
.heli-pill-sm{font-family:'Inter',system-ui,sans-serif;font-weight:700;font-size:10px;white-space:nowrap;padding:2px 6px;border-radius:3px;background:rgba(255,255,255,.88);box-shadow:0 1px 3px rgba(0,0,0,.15);color:#555;border-left:3px solid #888}
/* Marker: weiße Kreise mit Rahmen */
.marker-circle{width:26px;height:26px;background:#fff;border:2.5px solid #1f4e5a;border-radius:50%;box-shadow:0 2px 6px rgba(0,0,0,.3);display:flex;align-items:center;justify-content:center;font-size:13px;line-height:1}
.marker-circle.capital{border-color:#e8833a;width:30px;height:30px;font-size:15px}
.marker-circle.peak{border-color:#5a8a5e;width:24px;height:24px;font-size:12px}
.marker-circle.heli-m{border-color:#d4a017;width:30px;height:30px;font-size:16px}
.marker-circle.heli-m.inactive{width:22px;height:22px;font-size:11px;border-color:#888;opacity:.7}
/* Stadt-Pills */
.city-pill{font-family:'Inter',system-ui,sans-serif;font-weight:700;font-size:11px;white-space:nowrap;padding:4px 10px;border-radius:5px;background:rgba(218,232,236,.94);box-shadow:0 1px 4px rgba(0,0,0,.15);color:#1f4e5a;border-bottom:2.5px solid #4a7c8a;display:flex;align-items:center;height:22px}
.city-pill.capital{color:#e8833a;background:rgba(232,200,170,.92);border-bottom-color:#e8833a}
.city-pill .city-pop{font-size:8px;font-weight:500;color:#8a8a8a;margin-left:4px}
/* Berg-Pills */
.peak-pill{font-family:'Inter',system-ui,sans-serif;font-weight:700;font-size:10px;white-space:nowrap;padding:4px 9px;border-radius:5px;background:rgba(220,234,221,.94);box-shadow:0 1px 4px rgba(0,0,0,.12);color:#3a6b3e;border-bottom:2.5px solid #5a8a5e;display:flex;align-items:center;height:20px}
.peak-pill .peak-ele{font-size:8px;font-weight:500;color:#5a8a5e;margin-left:4px}
/* Quartett-Popup */
.heli-popup .leaflet-popup-content{margin:0;padding:0}
.heli-popup .leaflet-popup-content-wrapper{border-radius:12px;padding:0;overflow:hidden;box-shadow:0 4px 20px rgba(0,0,0,.15)}
.quartett{width:260px;font-family:'Inter',system-ui,sans-serif}
.quartett-img{height:140px;overflow:hidden;background:#f7f6f3;display:flex;align-items:center;justify-content:center}
.quartett-img img{width:100%;height:100%;object-fit:cover}
.quartett-body{padding:10px 12px 12px}
.quartett-name{font-size:13px;font-weight:800;color:#1f4e5a;margin-bottom:2px}
.quartett-org{font-size:10px;color:#8a8a8a;margin-bottom:8px}
.quartett-stats{display:grid;grid-template-columns:1fr 1fr;gap:4px}
.quartett-stat{background:#f7f6f3;border-radius:5px;padding:4px 6px}
.quartett-stat .qs-label{font-size:8px;color:#8a8a8a;font-weight:500}
.quartett-stat .qs-val{font-size:12px;font-weight:800;color:#1f4e5a}
.quartett-fact{margin-top:8px;font-size:10px;color:#4a4a4a;font-style:italic;line-height:1.4;border-top:1px solid #eee;padding-top:6px}
</style>
</head>
<body>
<div id="map"></div>
<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"></script>
<script>
var bounds = L.latLngBounds(L.latLng(46.3, 9.4), L.latLng(49.1, 17.2));
var map = L.map('map', {
zoomControl: false,
maxBounds: bounds.pad(0.05),
maxBoundsViscosity: 1.0,
minZoom: 7,
maxZoom: 15
}).setView([47.4, 13.2], 8);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a>',
maxZoom: 18
}).addTo(map);
L.control.zoom({position: 'topright'}).addTo(map);
L.control.scale({position: 'bottomleft', metric: true, imperial: false, maxWidth: 200}).addTo(map);
// === HUBSCHRAUBER-TYPEN (Quartett-Daten) ===
var HELI_TYPES = {
'EC135': {name:'Eurocopter EC135', img:'sims/heli/assets/heli-ec135.png', engines:2, crew:'1 Pilot + 1 Notarzt + 1 Sanitäter', maxSpeed:254, range:635, ceiling:6096, weight:2910, seats:6, role:'Rettung & Notfall', fact:'Der EC135 ist der meistgenutzte Rettungshubschrauber in Europa.', wiki:'https://de.wikipedia.org/wiki/Eurocopter_EC_135'},
'H145': {name:'Airbus H145', img:'sims/heli/assets/heli-h145.png', engines:2, crew:'12 Piloten + Rettungsteam', maxSpeed:268, range:680, ceiling:5485, weight:3700, seats:8, role:'Rettung & Intensivtransport', fact:'Der H145 kann auch bei Nacht und schlechtem Wetter fliegen (IFR).', wiki:'https://de.wikipedia.org/wiki/Airbus_Helicopters_H145'},
'AW169': {name:'Leonardo AW169', img:'sims/heli/assets/heli-aw169.png', engines:2, crew:'12 Piloten + Besatzung', maxSpeed:280, range:820, ceiling:4572, weight:4600, seats:10, role:'Polizei & Überwachung', fact:'Die Flugpolizei nennt ihre Hubschrauber „Libelle".', wiki:'https://de.wikipedia.org/wiki/Leonardo_AW169'},
'AB212': {name:'Agusta-Bell AB212', img:'sims/heli/assets/heli-ab212.png', engines:2, crew:'2 Piloten + Besatzung', maxSpeed:240, range:450, ceiling:4630, weight:5070, seats:14, role:'Militär & Katastrophenhilfe', fact:'Das Bundesheer setzt den AB212 seit den 1980er-Jahren ein.', wiki:'https://de.wikipedia.org/wiki/Agusta-Bell_AB_212'},
};
// === ALLE HUBSCHRAUBER-BASEN ÖSTERREICH ===
var bases = [
// Notarzt-Heli
{name:'Innsbruck OE-XVB', code:'C1', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.2600, lon:11.3439, active:true, heli:'EC135', region:'Innsbruck / Nordtirol'},
{name:'Krems OE-XVI', code:'C2', org:'Notarzt-Heli', orgClass:'oeamtc', lat:48.4306, lon:15.6100, active:false, heli:'EC135', region:'Gneixendorf / Waldviertel'},
{name:'Wr. Neustadt OE-XEL', code:'C3', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.8419, lon:16.2331, active:false, heli:'EC135', region:'Wiener Neustadt'},
{name:'Kitzbühel OE-XEY', code:'C4', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.3801, lon:12.3580, active:true, heli:'H145', region:'Reith bei Kitzbühel'},
{name:'Zams OE-XEZ', code:'C5', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.1597, lon:10.5933, active:true, heli:'H145', region:'Zams / Oberinntal'},
{name:'Salzburg OE-XVL', code:'C6', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.7950, lon:13.0044, active:false, heli:'H145', region:'Salzburg'},
{name:'Lienz OE-XER', code:'C7', org:'Notarzt-Heli', orgClass:'oeamtc', lat:46.8297, lon:12.7647, active:true, heli:'EC135', region:'Lienz / Osttirol'},
{name:'Nenzing OE-XEN', code:'C8', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.1828, lon:9.7072, active:true, heli:'H145', region:'Nenzing / Vorarlberg'},
{name:'Wien-Aspern OE-XVO', code:'C9', org:'Notarzt-Heli', orgClass:'oeamtc', lat:48.1172, lon:16.5025, active:false, heli:'EC135', region:'Wien'},
{name:'Linz OE-XVP', code:'C10', org:'Notarzt-Heli', orgClass:'oeamtc', lat:48.2331, lon:14.1875, active:false, heli:'EC135', region:'Linz'},
{name:'Klagenfurt OE-XEK', code:'C11', org:'Notarzt-Heli', orgClass:'oeamtc', lat:46.6503, lon:14.3372, active:false, heli:'EC135', region:'Klagenfurt'},
{name:'Graz OE-XEM', code:'C12', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.0094, lon:15.4106, active:false, heli:'EC135', region:'Graz'},
{name:'Niederöblarn OE-XEW', code:'C14', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.4756, lon:14.0042, active:false, heli:'H145', region:'Niederöblarn'},
{name:'Ybbsitz OE-XSA', code:'C15', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.9483, lon:14.8894, active:false, heli:'EC135', region:'Ybbsitz'},
{name:'Pinkafeld OE-XEU', code:'C16', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.2886, lon:16.2069, active:false, heli:'EC135', region:'Oberwart'},
{name:'Vomp OE-XAB', code:'C17', org:'Notarzt-Heli', orgClass:'oeamtc', lat:47.3500, lon:11.7000, active:false, heli:'EC135', region:'Vomp / Inntal'},
// ARA Flugrettung
{name:'Alpin 1 Reutte', code:'RK1', org:'ARA Flugrettung', orgClass:'ara', lat:47.4858, lon:10.7181, active:true, heli:'H145', region:'Reutte / Außerfern'},
{name:'Alpin 2 Fresach', code:'RK2', org:'ARA Flugrettung', orgClass:'ara', lat:46.7250, lon:13.6825, active:false, heli:'H145', region:'Fresach / Kärnten'},
{name:'Alpin 3 Ybbsitz', code:'RK3', org:'ARA Flugrettung', orgClass:'ara', lat:47.9500, lon:14.8900, active:false, heli:'EC135', region:'Ybbsitz / Mostviertel'},
{name:'Alpin 5 Salzburg', code:'RK5', org:'ARA Flugrettung', orgClass:'ara', lat:47.7933, lon:13.0100, active:false, heli:'H145', region:'Salzburg'},
{name:'Alpin 6 Linz', code:'RK6', org:'ARA Flugrettung', orgClass:'ara', lat:48.2333, lon:14.2000, active:false, heli:'EC135', region:'Linz'},
// Polizei/BMI Flugpolizei
{name:'Libelle Innsbruck', code:'LIB-I', org:'Flugpolizei BMI', orgClass:'police', lat:47.2583, lon:11.3556, active:true, heli:'AW169', region:'Innsbruck'},
{name:'Hohenems (Flugplatz)', code:'LIB-H', org:'Flugpolizei BMI', orgClass:'police', lat:47.38154, lon:9.69851, active:true, heli:'AW169', region:'Hohenems / Rheintal'},
{name:'Libelle Wien', code:'LIB-W', org:'Flugpolizei BMI', orgClass:'police', lat:48.1103, lon:16.5697, active:false, heli:'AW169', region:'Wien'},
{name:'Libelle Salzburg', code:'LIB-S', org:'Flugpolizei BMI', orgClass:'police', lat:47.7933, lon:13.0033, active:false, heli:'AW169', region:'Salzburg'},
{name:'Libelle Klagenfurt', code:'LIB-K', org:'Flugpolizei BMI', orgClass:'police', lat:46.6428, lon:14.3375, active:false, heli:'AW169', region:'Klagenfurt'},
{name:'Libelle Linz', code:'LIB-L', org:'Flugpolizei BMI', orgClass:'police', lat:48.2400, lon:14.1867, active:false, heli:'AW169', region:'Linz'},
{name:'Libelle Graz', code:'LIB-G', org:'Flugpolizei BMI', orgClass:'police', lat:47.0094, lon:15.4400, active:false, heli:'AW169', region:'Graz'},
// Bundesheer
{name:'Aigen im Ennstal', code:'BH-A', org:'Bundesheer', orgClass:'bh', lat:47.5236, lon:14.1350, active:false, heli:'AB212', region:'Aigen / Ennstal'},
{name:'Höttinger Au', code:'BH-I', org:'Bundesheer', orgClass:'bh', lat:47.2722, lon:11.3753, active:true, heli:'AB212', region:'Innsbruck'},
{name:'Langenlebarn', code:'BH-L', org:'Bundesheer', orgClass:'bh', lat:48.3239, lon:15.9836, active:false, heli:'AB212', region:'Langenlebarn / Tullnerfeld'},
// Krankenhaus-Landeplätze
{name:'LKH Innsbruck', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:47.2636, lon:11.3833, active:false},
{name:'LKH Feldkirch', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:47.2400, lon:9.5956, active:false},
{name:'AKH Wien', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:48.2206, lon:16.3453, active:false},
{name:'LKH Salzburg', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:47.7989, lon:13.0333, active:false},
{name:'LKH Graz', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:47.0808, lon:15.4678, active:false},
{name:'KH Kufstein', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:47.5836, lon:12.1647, active:false},
{name:'KH St. Johann', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:47.3528, lon:12.4247, active:false},
{name:'KH Zams', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:47.1575, lon:10.5917, active:false},
{name:'BKH Lienz', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:46.8300, lon:12.7700, active:false},
{name:'LKH Bregenz', code:'KH', org:'Krankenhaus', orgClass:'oeamtc', lat:47.4997, lon:9.7431, active:false},
];
function makeHeliPopup(b) {
var t = HELI_TYPES[b.heli];
if (!t) return '<strong>' + b.name + '</strong><br>' + b.org;
var bp = location.pathname.substring(0, location.pathname.lastIndexOf('/') + 1);
return '<div class="quartett">'
+ '<div class="quartett-img"><img src="' + bp + t.img + '" alt="' + t.name + '"></div>'
+ '<div class="quartett-body">'
+ '<div class="quartett-name">' + b.code + ' — ' + b.name + '</div>'
+ '<div class="quartett-org">' + b.org + ' · ' + (b.region||'') + '</div>'
+ '<div class="quartett-stats">'
+ '<div class="quartett-stat"><div class="qs-label">Typ</div><div class="qs-val">' + t.name + '</div></div>'
+ '<div class="quartett-stat"><div class="qs-label">Max. Speed</div><div class="qs-val">' + t.maxSpeed + ' km/h</div></div>'
+ '<div class="quartett-stat"><div class="qs-label">Reichweite</div><div class="qs-val">' + t.range + ' km</div></div>'
+ '<div class="quartett-stat"><div class="qs-label">Gipfelhöhe</div><div class="qs-val">' + t.ceiling + ' m</div></div>'
+ '<div class="quartett-stat"><div class="qs-label">Triebwerke</div><div class="qs-val">' + t.engines + '</div></div>'
+ '<div class="quartett-stat"><div class="qs-label">Besatzung</div><div class="qs-val">' + t.crew + '</div></div>'
+ '</div>'
+ '<div class="quartett-fact">💡 ' + t.fact + '</div>'
+ (t.wiki ? '<div style="text-align:center;margin-top:6px"><a href="'+t.wiki+'" target="_blank" style="font-size:10px;color:#4a7c8a;text-decoration:none;font-weight:600">📖 Wikipedia →</a></div>' : '')
+ '</div></div>';
}
bases.forEach(function(b) {
var size = b.active ? 30 : 22;
var circleClass = b.active ? 'marker-circle heli-m' : 'marker-circle heli-m inactive';
L.marker([b.lat, b.lon], {
icon: L.divIcon({
className: '',
html: '<div class="' + circleClass + '">🚁</div>',
iconSize: [size, size],
iconAnchor: [size/2, size/2]
}),
title: b.name + ' (' + b.org + ')',
zIndexOffset: b.active ? 1000 : 0
}).addTo(map).bindPopup(makeHeliPopup(b), {maxWidth:280, className:'heli-popup'});
// Pill-Label
if (b.active) {
L.marker([b.lat, b.lon], {
icon: L.divIcon({
className: 'heli-pill ' + b.orgClass,
html: '<span class="pill-name">' + b.code + ' ' + b.name + '</span><span class="pill-org">' + b.org + '</span>',
iconSize: [160, 28],
iconAnchor: [-20, 14]
}),
interactive: false,
zIndexOffset: 900
}).addTo(map);
} else {
L.marker([b.lat, b.lon], {
icon: L.divIcon({
className: 'heli-pill-sm',
html: b.code,
iconSize: [40, 14],
iconAnchor: [-10, 7]
}),
interactive: false
}).addTo(map);
}
});
// === STÄDTE >30.000 EW + Bregenz ===
var cities = [
{name:'Wien', lat:48.2082, lon:16.3738, pop:1982097, capital:true, land:'Wien', fun:'Hat mehr Einwohner*innen als alle anderen Landeshauptstädte zusammen!', fact:'Wurde 5× zur lebenswertesten Stadt der Welt gewählt.', wiki:'https://de.wikipedia.org/wiki/Wien', img:'sims/heli/assets/cities/wien.png'},
{name:'Graz', lat:47.0707, lon:15.4395, pop:295424, capital:true, land:'Steiermark', fun:'Die Altstadt ist UNESCO-Weltkulturerbe.', fact:'Zweitgrößte Stadt Österreichs, Universitätsstadt mit über 60.000 Studierenden.', wiki:'https://de.wikipedia.org/wiki/Graz', img:'sims/heli/assets/cities/graz.png'},
{name:'Linz', lat:48.3069, lon:14.2858, pop:210118, capital:true, land:'Oberösterreich', fun:'War 2009 Europäische Kulturhauptstadt.', fact:'Wichtigster Industriestandort Österreichs (Stahl, Chemie).', wiki:'https://de.wikipedia.org/wiki/Linz', img:'sims/heli/assets/cities/linz.png'},
{name:'Salzburg', lat:47.8095, lon:13.0550, pop:157745, capital:true, land:'Salzburg', fun:'Geburtsstadt von Wolfgang Amadeus Mozart (1756).', fact:'Die Altstadt gehört zum UNESCO-Weltkulturerbe.', wiki:'https://de.wikipedia.org/wiki/Salzburg', img:'sims/heli/assets/cities/salzburg.png'},
{name:'Innsbruck', lat:47.2654, lon:11.3928, pop:130585, capital:true, land:'Tirol', fun:'Hat schon 3× Olympische Winterspiele ausgerichtet!', fact:'Liegt auf 574 m im Inntal, umgeben von Bergen bis 2.300 m.', wiki:'https://de.wikipedia.org/wiki/Innsbruck', img:'sims/heli/assets/cities/innsbruck.png'},
{name:'Klagenfurt', lat:46.6247, lon:14.3050, pop:103671, capital:true, land:'Kärnten', fun:'Am Wörthersee — einem der wärmsten Badeseen der Alpen.', fact:'Südlichste Landeshauptstadt Österreichs.', wiki:'https://de.wikipedia.org/wiki/Klagenfurt_am_Wörthersee', img:'sims/heli/assets/cities/klagenfurt.png'},
{name:'Villach', lat:46.6111, lon:13.8558, pop:65127, capital:false, land:'Kärnten', fun:'Hat einen eigenen Fasching — den Villacher Fasching!', fact:'Zweitgrößte Stadt Kärntens, wichtiger Verkehrsknotenpunkt Richtung Italien/Slowenien.', wiki:'https://de.wikipedia.org/wiki/Villach', img:'sims/heli/assets/cities/villach.png'},
{name:'Wels', lat:48.1575, lon:14.0289, pop:63539, capital:false, land:'Oberösterreich', fun:'Hier findet die größte Agrarmesse Österreichs statt.', fact:'Zweitgrößte Stadt Oberösterreichs.', wiki:'https://de.wikipedia.org/wiki/Wels_(Stadt)', img:'sims/heli/assets/cities/wels.png'},
{name:'St. Pölten', lat:48.2047, lon:15.6256, pop:57169, capital:true, land:'Niederösterreich', fun:'Jüngste Landeshauptstadt — erst seit 1986!', fact:'Vorher war Wien auch Hauptstadt von Niederösterreich.', wiki:'https://de.wikipedia.org/wiki/St._Pölten', img:'sims/heli/assets/cities/stpoelten.png'},
{name:'Dornbirn', lat:47.4136, lon:9.7424, pop:51222, capital:false, land:'Vorarlberg', fun:'Größte Stadt Vorarlbergs — nicht Bregenz!', fact:'Wichtiger Messestandort und Wirtschaftszentrum im Rheintal.', wiki:'https://de.wikipedia.org/wiki/Dornbirn', img:'sims/heli/assets/cities/dornbirn.png'},
{name:'Wiener Neustadt', lat:47.8133, lon:16.2467, pop:48519, capital:false, land:'Niederösterreich', fun:'Hier wurde die erste Militärakademie der Welt gegründet (1752).', fact:'Wichtiger Standort des Bundesheers.', wiki:'https://de.wikipedia.org/wiki/Wiener_Neustadt', img:'sims/heli/assets/cities/wiener_neustadt.png'},
{name:'Steyr', lat:48.0386, lon:14.4214, pop:38572, capital:false, land:'Oberösterreich', fun:'Die Altstadt sieht aus wie ein Märchen — mit Flüssen und mittelalterlichen Häusern.', fact:'Berühmt für Stahl und Waffen seit dem Mittelalter.', wiki:'https://de.wikipedia.org/wiki/Steyr', img:'sims/heli/assets/cities/steyr.png'},
{name:'Feldkirch', lat:47.2376, lon:9.5982, pop:35793, capital:false, land:'Vorarlberg', fun:'Hat eine echte mittelalterliche Burg — die Schattenburg.', fact:'Grenzstadt zur Schweiz und Liechtenstein.', wiki:'https://de.wikipedia.org/wiki/Feldkirch', img:'sims/heli/assets/cities/feldkirch.png'},
{name:'Bregenz', lat:47.5026, lon:9.7473, pop:29620, capital:true, land:'Vorarlberg', fun:'Die Seebühne auf dem Bodensee ist die größte Freilichtbühne der Welt!', fact:'Kleinste Landeshauptstadt Österreichs.', wiki:'https://de.wikipedia.org/wiki/Bregenz', img:'sims/heli/assets/cities/bregenz.png'},
{name:'Leoben', lat:47.3765, lon:15.0910, pop:32768, capital:false, land:'Steiermark', fun:'Hier wird an der Montanuniversität Bergbau studiert.', fact:'War jahrhundertelang das Zentrum des steirischen Erzbergbaus.', wiki:'https://de.wikipedia.org/wiki/Leoben', img:'sims/heli/assets/cities/leoben.png'},
{name:'Eisenstadt', lat:47.8456, lon:16.5189, pop:15073, capital:true, land:'Burgenland', fun:'Hier lebte der Komponist Joseph Haydn über 30 Jahre.', fact:'Kleinste Landeshauptstadt nach Einwohnern. Schloss Esterházy ist das Wahrzeichen.', wiki:'https://de.wikipedia.org/wiki/Eisenstadt', img:'sims/heli/assets/cities/eisenstadt.png'},
];
cities.forEach(function(c) {
var dotSize = c.capital ? 30 : 26;
var cls = '';
// Punkt
var capitalBadge = c.capital ? '<div style="display:inline-block;background:#e8833a;color:#fff;font-size:9px;font-weight:700;padding:2px 8px;border-radius:99px;margin-bottom:6px">★ Landeshauptstadt' + (c.land ? ' von ' + c.land : '') + '</div>' : (c.land ? '<div style="font-size:10px;color:#8a8a8a;margin-bottom:4px">' + c.land + '</div>' : '');
L.marker([c.lat, c.lon], {
icon: L.divIcon({
className: cls,
html: '<div class="marker-circle' + (c.capital ? ' capital' : '') + '">🏙️</div>',
iconSize: [dotSize, dotSize],
iconAnchor: [dotSize/2, dotSize/2]
}),
zIndexOffset: c.capital ? 500 : 100
}).addTo(map).bindPopup(
'<div style="font-family:Inter,sans-serif;width:260px;padding:0">'
+ (c.img ? '<div style="height:130px;overflow:hidden;border-radius:8px 8px 0 0;margin:-12px -12px 8px"><img src="'+c.img+'" style="width:100%;height:100%;object-fit:cover"></div>' : '')
+ '<div style="text-align:center">'
+ capitalBadge
+ '<div style="font-size:16px;font-weight:900;color:#1f4e5a;margin-bottom:2px">' + c.name + '</div>'
+ '<div style="font-size:22px;font-weight:900;color:#4a7c8a">' + c.pop.toLocaleString() + '</div>'
+ '<div style="font-size:9px;color:#8a8a8a;margin-bottom:8px">Einwohner*innen</div>'
+ '</div>'
+ (c.fun ? '<div style="font-size:11px;color:#2d5434;background:rgba(90,138,94,.08);border-radius:6px;padding:6px 8px;margin-bottom:6px">🎯 ' + c.fun + '</div>' : '')
+ (c.fact ? '<div style="font-size:11px;color:#4a4a4a;line-height:1.4;margin-bottom:6px">📚 ' + c.fact + '</div>' : '')
+ (c.wiki ? '<div style="text-align:center"><a href="'+c.wiki+'" target="_blank" style="font-size:10px;color:#4a7c8a;text-decoration:none;font-weight:600">📖 Wikipedia →</a></div>' : '')
+ '</div>'
, {maxWidth:260});
// Pill
var popStr = c.pop >= 1000000 ? (c.pop/1000000).toFixed(1) + ' Mio' : Math.round(c.pop/1000) + 'k';
var star = c.capital ? ' ★' : '';
L.marker([c.lat, c.lon], {
icon: L.divIcon({
className: 'city-pill' + (c.capital ? ' capital' : ''),
html: c.name + star + '<span class="city-pop">' + popStr + '</span>',
iconSize: [140, 22],
iconAnchor: [-16, 11]
}),
interactive: false,
zIndexOffset: c.capital ? 400 : 50
}).addTo(map);
});
// === BERGGIPFEL ===
var peaks = [
{name:'Großglockner', lat:47.0742, lon:12.6947, ele:3798, fact:'Höchster Berg Österreichs! Die berühmte Großglockner Hochalpenstraße führt bis auf 2.504 m.', wiki:'https://de.wikipedia.org/wiki/Großglockner'},
{name:'Wildspitze', lat:46.8853, lon:10.8672, ele:3768, fact:'Höchster Berg Tirols und zweithöchster Österreichs. Hat den größten Gletscher der Ostalpen.', wiki:'https://de.wikipedia.org/wiki/Wildspitze'},
{name:'Weißkugel', lat:46.8439, lon:10.7833, ele:3738, fact:'Dritthöchster Berg Österreichs, direkt an der Grenze zu Italien.', wiki:'https://de.wikipedia.org/wiki/Weißkugel'},
{name:'Großvenediger', lat:47.1092, lon:12.3464, ele:3657, fact:'Wird „Weltalte Majestät" genannt. Einer der schönsten Gletscherberge der Alpen.', wiki:'https://de.wikipedia.org/wiki/Großvenediger'},
{name:'Similaun', lat:46.7578, lon:10.8853, ele:3599, fact:'Hier wurde 1991 die Gletschermumie „Ötzi" gefunden — 5.300 Jahre alt!', wiki:'https://de.wikipedia.org/wiki/Similaun'},
{name:'Zuckerhütl', lat:46.9833, lon:11.1167, ele:3505, fact:'Höchster Berg der Stubaier Alpen. Beliebtes Ziel für Skitouren.', wiki:'https://de.wikipedia.org/wiki/Zuckerhütl'},
{name:'Piz Buin', lat:46.8444, lon:10.1186, ele:3312, fact:'Höchster Berg Vorarlbergs. Die Sonnencreme-Marke wurde nach ihm benannt!', wiki:'https://de.wikipedia.org/wiki/Piz_Buin'},
{name:'Zugspitze', lat:47.4211, lon:10.9856, ele:2962, fact:'Höchster Berg Deutschlands, direkt an der Grenze zu Österreich. Seilbahn fährt bis zum Gipfel.', wiki:'https://de.wikipedia.org/wiki/Zugspitze'},
{name:'Dachstein', lat:47.4753, lon:13.6061, ele:2995, fact:'Höchster Berg der Steiermark. Hat eine Eishöhle und den berühmten Skywalk.', wiki:'https://de.wikipedia.org/wiki/Hoher_Dachstein'},
{name:'Valluga', lat:47.1567, lon:10.2117, ele:2809, fact:'Hausberg von St. Anton am Arlberg, eines der berühmtesten Skigebiete der Welt.', wiki:'https://de.wikipedia.org/wiki/Valluga'},
{name:'Parseierspitze', lat:47.0825, lon:10.5086, ele:3036, fact:'Höchster Berg der Lechtaler Alpen. Nur für erfahrene Bergsteiger*innen!', wiki:'https://de.wikipedia.org/wiki/Parseierspitze'},
{name:'Brenner', lat:47.0422, lon:11.5067, ele:1370, fact:'Der wichtigste Alpenpass zwischen Österreich und Italien. Schon die Römer nutzten ihn.', wiki:'https://de.wikipedia.org/wiki/Brennerpass'},
{name:'Patscherkofel', lat:47.2083, lon:11.4611, ele:2246, fact:'Hausberg von Innsbruck. Hier fanden Olympische Skirennen statt.', wiki:'https://de.wikipedia.org/wiki/Patscherkofel'},
{name:'Arlberg', lat:47.1297, lon:10.2119, ele:1793, fact:'Grenze zwischen Tirol und Vorarlberg. Wiege des alpinen Skilaufs.', wiki:'https://de.wikipedia.org/wiki/Arlberg'},
];
peaks.forEach(function(p) {
L.marker([p.lat, p.lon], {
icon: L.divIcon({
className: '',
html: '<div class="marker-circle peak">🏔️</div>',
iconSize: [24, 24],
iconAnchor: [12, 12]
})
}).addTo(map).bindPopup(
'<div style="font-family:Inter,sans-serif;width:220px;padding:2px">'
+ '<div style="text-align:center">'
+ '<div style="font-size:2.5rem">🏔️</div>'
+ '<div style="font-size:15px;font-weight:900;color:#3a6b3e">' + p.name + '</div>'
+ '<div style="font-size:24px;font-weight:900;color:#1f4e5a">' + p.ele.toLocaleString() + ' m</div>'
+ '</div>'
+ (p.fact ? '<div style="font-size:11px;color:#4a4a4a;line-height:1.4;margin:8px 0 4px;background:rgba(90,138,94,.06);border-radius:6px;padding:6px 8px">🌿 ' + p.fact + '</div>' : '')
+ (p.wiki ? '<div style="text-align:center"><a href="'+p.wiki+'" target="_blank" style="font-size:10px;color:#4a7c8a;text-decoration:none;font-weight:600">📖 Wikipedia →</a></div>' : '')
+ '</div>'
, {maxWidth:240});
L.marker([p.lat, p.lon], {
icon: L.divIcon({
className: 'peak-pill',
html: p.name + '<span class="peak-ele">' + p.ele.toLocaleString() + ' m</span>',
iconSize: [140, 20],
iconAnchor: [-14, 10]
}),
interactive: false
}).addTo(map);
});
// === DB-SYNC: Koordinaten aus der Datenbank laden und Marker aktualisieren ===
(async function() {
try {
var bp = location.pathname.replace(/\/[^\/]*$/, '');
var resp = await fetch(bp + '/api/waypoints');
var dbWaypoints = await resp.json();
if (!Array.isArray(dbWaypoints)) return;
// Index nach wp_key
var dbMap = {};
dbWaypoints.forEach(function(w) { dbMap[w.wp_key] = {lat: parseFloat(w.lat), lon: parseFloat(w.lon), name: w.name}; });
// Alle Leaflet-Marker durchgehen und Positionen updaten
map.eachLayer(function(layer) {
if (layer.getLatLng && layer.options && layer.options.title) {
// Versuche den Marker anhand des Titels zu identifizieren
// (Heli-Basen haben title gesetzt)
}
});
// Einfacher: Seite neu rendern wenn DB-Daten signifikant abweichen
// Für jetzt: Konsolenwarnung bei Abweichungen
var fixes = 0;
bases.forEach(function(b) {
var key = b.name.toLowerCase().replace(/[^a-z0-9]/g,'');
// Versuche verschiedene Key-Matches
for (var dbKey in dbMap) {
if (dbMap[dbKey].name === b.name || dbMap[dbKey].name.indexOf(b.code) !== -1) {
var dLat = Math.abs(b.lat - dbMap[dbKey].lat);
var dLon = Math.abs(b.lon - dbMap[dbKey].lon);
if (dLat > 0.001 || dLon > 0.001) {
console.warn('DB-Korrektur: ' + b.name + ' (' + b.lat + ',' + b.lon + ') → (' + dbMap[dbKey].lat + ',' + dbMap[dbKey].lon + ')');
fixes++;
}
break;
}
}
});
// Marker-Positionen korrigieren: alle Layer entfernen und neu setzen
if (Object.keys(dbMap).length > 0) {
// Alle bestehenden Marker entfernen
var layersToRemove = [];
map.eachLayer(function(layer) {
if (layer.getLatLng && !(layer instanceof L.TileLayer)) {
layersToRemove.push(layer);
}
});
layersToRemove.forEach(function(l) { map.removeLayer(l); });
// Basen neu setzen mit DB-Koordinaten
bases.forEach(function(b) {
// Finde passenden DB-Eintrag
for (var dbKey in dbMap) {
if (dbMap[dbKey].name.indexOf(b.code) !== -1 || dbMap[dbKey].name === b.name) {
b.lat = dbMap[dbKey].lat;
b.lon = dbMap[dbKey].lon;
break;
}
}
var size = b.active ? 30 : 22;
var circleClass = b.active ? 'marker-circle heli-m' : 'marker-circle heli-m inactive';
L.marker([b.lat, b.lon], {
icon: L.divIcon({className:'', html:'<div class="'+circleClass+'">🚁</div>', iconSize:[size,size], iconAnchor:[size/2,size/2]}),
title: b.name+' ('+b.org+')', zIndexOffset: b.active ? 1000 : 0
}).addTo(map).bindPopup(makeHeliPopup(b), {maxWidth:280, className:'heli-popup'});
if (b.active) {
L.marker([b.lat, b.lon], {
icon: L.divIcon({className:'heli-pill '+b.orgClass, html:'<span class="pill-name">'+b.code+' '+b.name+'</span><span class="pill-org">'+b.org+'</span>', iconSize:[160,28], iconAnchor:[-20,14]}),
interactive:false, zIndexOffset:900
}).addTo(map);
}
});
// Städte neu setzen
cities.forEach(function(c) {
var dbKey = c.name.toLowerCase().replace(/[^a-zäöüß]/g,'');
for (var k in dbMap) {
if (dbMap[k].name.toLowerCase().replace(/[^a-zäöüß]/g,'') === dbKey) {
c.lat = dbMap[k].lat; c.lon = dbMap[k].lon; break;
}
}
var dotSize = c.capital ? 30 : 26;
var capitalBadge = c.capital ? '<div style="display:inline-block;background:#e8833a;color:#fff;font-size:9px;font-weight:700;padding:2px 8px;border-radius:99px;margin-bottom:6px">★ Landeshauptstadt'+(c.land?' von '+c.land:'')+'</div>' : (c.land?'<div style="font-size:10px;color:#8a8a8a;margin-bottom:4px">'+c.land+'</div>':'');
L.marker([c.lat, c.lon], {
icon: L.divIcon({className:'', html:'<div class="marker-circle'+(c.capital?' capital':'')+'">🏙️</div>', iconSize:[dotSize,dotSize], iconAnchor:[dotSize/2,dotSize/2]}),
zIndexOffset: c.capital ? 500 : 100
}).addTo(map).bindPopup(
'<div style="font-family:Inter,sans-serif;width:260px;padding:0">'
+(c.img?'<div style="height:130px;overflow:hidden;border-radius:8px 8px 0 0;margin:-12px -12px 8px"><img src="'+c.img+'" style="width:100%;height:100%;object-fit:cover"></div>':'')
+'<div style="text-align:center">'+capitalBadge
+'<div style="font-size:16px;font-weight:900;color:#1f4e5a;margin-bottom:2px">'+c.name+'</div>'
+'<div style="font-size:22px;font-weight:900;color:#4a7c8a">'+c.pop.toLocaleString()+'</div>'
+'<div style="font-size:9px;color:#8a8a8a;margin-bottom:8px">Einwohner*innen</div></div>'
+(c.fun?'<div style="font-size:11px;color:#2d5434;background:rgba(90,138,94,.08);border-radius:6px;padding:6px 8px;margin-bottom:6px">🎯 '+c.fun+'</div>':'')
+(c.fact?'<div style="font-size:11px;color:#4a4a4a;line-height:1.4;margin-bottom:6px">📚 '+c.fact+'</div>':'')
+(c.wiki?'<div style="text-align:center"><a href="'+c.wiki+'" target="_blank" style="font-size:10px;color:#4a7c8a;text-decoration:none;font-weight:600">📖 Wikipedia →</a></div>':'')
+'</div>', {maxWidth:260});
var star = c.capital ? ' ★' : '';
var popStr = c.pop >= 1000000 ? (c.pop/1000000).toFixed(1)+' Mio' : Math.round(c.pop/1000)+'k';
L.marker([c.lat, c.lon], {
icon: L.divIcon({className:'city-pill'+(c.capital?' capital':''), html:c.name+star+'<span class="city-pop">'+popStr+'</span>', iconSize:[140,22], iconAnchor:[-16,11]}),
interactive:false, zIndexOffset: c.capital ? 400 : 50
}).addTo(map);
});
// Berge neu setzen
peaks.forEach(function(p) {
L.marker([p.lat, p.lon], {
icon: L.divIcon({className:'', html:'<div class="marker-circle peak">🏔️</div>', iconSize:[24,24], iconAnchor:[12,12]})
}).addTo(map).bindPopup(
'<div style="font-family:Inter,sans-serif;width:220px;padding:2px"><div style="text-align:center">'
+'<div style="font-size:2.5rem">🏔️</div><div style="font-size:15px;font-weight:900;color:#3a6b3e">'+p.name+'</div>'
+'<div style="font-size:24px;font-weight:900;color:#1f4e5a">'+p.ele.toLocaleString()+' m</div></div>'
+(p.fact?'<div style="font-size:11px;color:#4a4a4a;line-height:1.4;margin:8px 0 4px;background:rgba(90,138,94,.06);border-radius:6px;padding:6px 8px">🌿 '+p.fact+'</div>':'')
+(p.wiki?'<div style="text-align:center"><a href="'+p.wiki+'" target="_blank" style="font-size:10px;color:#4a7c8a;text-decoration:none;font-weight:600">📖 Wikipedia →</a></div>':'')
+'</div>', {maxWidth:240});
L.marker([p.lat, p.lon], {
icon: L.divIcon({className:'peak-pill', html:p.name+'<span class="peak-ele">'+p.ele.toLocaleString()+' m</span>', iconSize:[140,20], iconAnchor:[-14,10]}),
interactive:false
}).addTo(map);
});
console.log('Karte mit DB-Koordinaten aktualisiert (' + Object.keys(dbMap).length + ' Waypoints)');
}
} catch(e) { console.warn('DB-Sync fehlgeschlagen:', e); }
})();
</script>
</body>
</html>
@@ -1,71 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<title>toDelete/ · Entwurfswerkzeug</title>
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',system-ui,sans-serif;background:#f5f2eb;color:#2a2a2a;line-height:1.5;padding:24px;max-width:1100px;margin:0 auto}
h1{color:#1f4e5a;font-size:1.5rem;margin-bottom:4px}
.sub{font-size:.82rem;color:#8a8a8a;margin-bottom:14px}
h2{color:#1f4e5a;font-size:1.05rem;margin:20px 0 8px;padding-bottom:4px;border-bottom:2px solid #4a7c8a}
table{width:100%;border-collapse:collapse;font-size:.86rem;background:#fff;border-radius:6px;overflow:hidden}
th,td{text-align:left;padding:8px 12px;border-bottom:1px solid #e0ddd4;vertical-align:top}
th{background:#9c4d2e;color:#fff;font-weight:600;font-size:.74rem;text-transform:uppercase;letter-spacing:.04em}
tr:last-child td{border-bottom:none}
code{background:#f5f2eb;padding:2px 6px;border-radius:3px;font-family:'JetBrains Mono',Consolas,monospace;font-size:.85em}
a{color:#1f4e5a}
.danger-box{background:#fde0db;border-left:4px solid #c85c4a;padding:10px 14px;margin:12px 0;border-radius:0 6px 6px 0;font-size:.86rem}
/* einheitliches Entwurfswerkzeug-Menü */
.top-nav{background:#fff;border:1px solid #e0ddd4;border-radius:8px;padding:10px 14px;margin-bottom:18px;font-size:.86rem;display:flex;flex-wrap:wrap;gap:12px;align-items:center}
.top-nav strong{color:#1f4e5a}
.top-nav a{text-decoration:none;padding:5px 11px;border-radius:6px;color:#1f4e5a}
.top-nav a:hover{background:#f5f2eb}
.top-nav a.active{background:#9c4d2e;color:#fff}
</style>
</head>
<body>
<nav class="top-nav">
<strong>🛠 Entwurfswerkzeug</strong>
<a href="../index.html">Übersicht</a>
<a href="../../entwurf.html">Entwurf</a>
<a href="../../review.html">Review</a>
<a href="../accounts.html">🔑 Accounts</a>
<a href="../standards.html">📐 Standards</a>
<a href="../legacy/" style="color:#6b6448">📂 legacy/</a>
<a href="index.html" class="active">📂 toDelete/</a>
<a href="../../../App/admin-sitemap.html" target="_blank">📊 Sitemap</a>
</nav>
<h1>📂 toDelete/</h1>
<p class="sub">10 Top-Level-Pages aus der Prod entfernt (Sweep 2026-06-08). Warten auf finale Lösch-Freigabe.</p>
<div class="danger-box">
<b>Wenn du eines davon brauchst:</b> einfach zurück mit
<code>git mv .dontDeploy/entwurfswerkzeug/toDelete/&lt;datei&gt; App/&lt;datei&gt;</code> — Historie bleibt erhalten.
</div>
<h2>📄 Lösch-Kandidaten</h2>
<table>
<thead><tr><th>Datei</th><th>Was es war</th><th>Status</th></tr></thead>
<tbody>
<tr><td><a href="dashboard.html"><code>dashboard.html</code></a></td><td>Demo-Mockup mit „alle Daten erfunden"-Banner</td><td>Ersetzt durch <code>App/teacher.html</code>. Endgültig löschbar.</td></tr>
<tr><td><a href="game.html"><code>game.html</code></a></td><td>Klima-2D Standalone vor Wrapper-System</td><td>Wrapper <code>pages/klima.php</code> ist Production. Löschbar.</td></tr>
<tr><td><a href="game-3d.html"><code>game-3d.html</code></a></td><td>Klima-3D Standalone</td><td>Wrapper <code>pages/klima-3d.php</code> ist Production. Löschbar.</td></tr>
<tr><td><a href="fluss.html"><code>fluss.html</code></a></td><td>Flussmanagement Standalone</td><td>Wrapper <code>pages/fluss.php</code> ist Production. Löschbar.</td></tr>
<tr><td><a href="heli.html"><code>heli.html</code></a></td><td>Heli-Navigation Standalone</td><td>Wrapper <code>pages/heli.php</code> ist Production. Löschbar.</td></tr>
<tr><td><a href="stadt.html"><code>stadt.html</code></a></td><td>Stadt-Simulation Standalone (nie fertig)</td><td>Stadt noch in Entwurf — beim Reaktivieren ggf. zurückholen.</td></tr>
<tr><td><a href="erdbeben.html"><code>erdbeben.html</code></a></td><td>Konzept-Stub Erdbeben-Sim</td><td>Konzept nie umgesetzt. Löschbar.</td></tr>
<tr><td><a href="energiemix.html"><code>energiemix.html</code></a></td><td>Konzept-Stub Energiemix</td><td>Ersetzt durch <code>energiemanager</code>. Löschbar.</td></tr>
<tr><td><a href="lieferketten.html"><code>lieferketten.html</code></a></td><td>Konzept-Stub Lieferketten</td><td>Konzept nie umgesetzt. Löschbar.</td></tr>
<tr><td><a href="regenwald.html"><code>regenwald.html</code></a></td><td>Konzept-Stub Regenwald</td><td>Konzept nie umgesetzt. Löschbar.</td></tr>
</tbody>
</table>
<footer style="margin:24px 0;text-align:center;font-size:.75rem;color:#8a8a8a">
Liegt unter <code>.dontDeploy/entwurfswerkzeug/toDelete/</code> · wird nicht deployed.
</footer>
</body>
</html>
@@ -1,545 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Lieferketten-Planer*in</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="assets/fonts/inter.css">
<style>
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
:root {
--bg: #f7f6f3;
--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;
--glass-bg: rgba(255,255,255,.85);
--glass-bg2: rgba(255,255,255,.92);
--glass-bord: rgba(255,255,255,.55);
--glass-shadow: 0 8px 32px rgba(20,40,60,.18);
--topbar-h: 2.8rem;
--side-w: 220px;
--pad: .65rem;
}
html, body { height:100%; overflow:hidden; }
body { font-family:'Inter',system-ui,sans-serif; background:#dceaf0; color:var(--text); line-height:1.5; }
#canvas-wrap { position:fixed; inset:0; z-index:0; }
/* === FLOATING PANELS === */
.floating {
position:fixed; z-index:5;
backdrop-filter:blur(14px) saturate(140%); -webkit-backdrop-filter:blur(14px) saturate(140%);
background:var(--glass-bg); border:1px solid var(--glass-bord);
box-shadow:var(--glass-shadow); border-radius:14px;
}
/* === TOPBAR === */
.topbar {
top:0; left:0; right:0;
padding:.35rem .7rem;
display:flex; justify-content:space-between; align-items:center; gap:.8rem;
border-radius:0; border-bottom:1px solid rgba(0,0,0,.08);
}
.topbar .brand {
display:flex; align-items:center; gap:.5rem; font-weight:800; font-size:.92rem;
color:var(--fjord); text-decoration:none; white-space:nowrap;
}
.topbar .brand img { width:24px; height:24px; border-radius:6px; }
.topbar-controls { display:flex; gap:.5rem; align-items:center; }
.icon-btn {
width:32px; height:32px; border-radius:8px;
border:1px solid rgba(0,0,0,.08); background:rgba(255,255,255,.55);
color:var(--text2); font-size:.95rem; cursor:pointer;
display:flex; align-items:center; justify-content:center; padding:0;
text-decoration:none; transition:all .15s;
}
.icon-btn:hover { background:var(--fjord-l); border-color:var(--fjord); color:var(--fjord); }
.ctrl-group {
display:flex; gap:.2rem; padding:.2rem;
background:rgba(255,255,255,.45); border-radius:9px;
border:1px solid rgba(0,0,0,.06);
}
.ctrl-group .icon-btn {
border:none; background:transparent;
width:30px; height:30px; font-size:.8rem; font-weight:700;
}
.ctrl-group .icon-btn:hover { background:rgba(0,0,0,.06); }
.ctrl-group .icon-btn.active { background:var(--fjord); color:#fff; }
.topbar-sep { width:1px; height:24px; background:rgba(0,0,0,.08); }
/* === STATUS-PANEL (LINKS) === */
.panel-h {
font-size:.58rem; font-weight:800; color:var(--fjord);
text-transform:uppercase; letter-spacing:.07em; margin-bottom:.4rem;
}
.panel-h-sub { margin-top:.9rem; padding-top:.6rem; border-top:1px solid rgba(0,0,0,.08); }
.panel-status {
top: calc(var(--topbar-h) + var(--pad));
left: var(--pad);
width: var(--side-w);
padding: .6rem .75rem;
bottom: var(--pad);
overflow-y: auto;
}
.resource {
display:flex; align-items:flex-start; gap:.5rem; padding:.3rem .1rem;
border-bottom:1px solid rgba(0,0,0,.06);
}
.resource:last-child { border-bottom:none; }
.resource-icon { font-size:1.15rem; width:22px; text-align:center; padding-top:.1rem; }
.resource-info { flex:1; min-width:0; }
.resource-name { font-size:.58rem; color:var(--text3); font-weight:500; line-height:1.1; }
.resource-val { font-size:.85rem; font-weight:800; color:var(--text); line-height:1.2; }
/* === GOALS === */
.goal { padding:.3rem 0; border-bottom:1px solid rgba(0,0,0,.06); }
.goal:last-child { border:0; }
.goal-row { display:flex; align-items:center; gap:.35rem; font-size:.7rem; }
.goal-check {
width:12px; height:12px; border:1.5px solid var(--text3);
border-radius:3px; display:flex; align-items:center; justify-content:center;
font-size:.52rem; flex-shrink:0;
}
.goal-check.done { background:var(--moss); border-color:var(--moss); color:#fff; }
.goal-bar { height:3px; background:rgba(0,0,0,.08); border-radius:2px; margin-top:.2rem; overflow:hidden; }
.goal-bar-fill { height:100%; background:var(--moss); transition:width .3s; }
/* === BESTELL-FORMULAR (RECHTS) === */
.panel-order {
top: calc(var(--topbar-h) + var(--pad));
right: var(--pad);
bottom: var(--pad);
width: 300px;
padding: .85rem 1rem 1rem;
overflow-y: auto;
}
.order-section { margin-bottom: 1rem; }
.order-section h4 {
font-size: .65rem; font-weight: 800; color: var(--fjord);
text-transform: uppercase; letter-spacing: .07em;
margin-bottom: .35rem;
}
.order-options { display: flex; flex-direction: column; gap: .25rem; }
.order-option {
display: flex; align-items: center; gap: .4rem;
padding: .35rem .5rem; border-radius: 8px;
background: rgba(255,255,255,.55);
border: 1.5px solid rgba(0,0,0,.06);
cursor: pointer; transition: all .12s;
font-family: inherit; text-align: left;
}
.order-option:hover { border-color: var(--fjord); background: var(--fjord-l); }
.order-option.selected { border-color: var(--moss); background: var(--moss-l); }
.oo-flag { font-size: .9rem; flex-shrink: 0; }
.oo-info { flex: 1; min-width: 0; }
.oo-name { font-size: .68rem; font-weight: 700; line-height: 1.15; }
.oo-stats {
font-size: .55rem; color: var(--text3); line-height: 1.2;
font-variant-numeric: tabular-nums;
}
.oo-stats .oo-stat { display: inline-block; margin-right: .35rem; }
.oo-stat-good { color: var(--moss); }
.oo-stat-bad { color: var(--danger); }
.transport-row { display: flex; gap: .25rem; }
.transport-btn {
flex: 1; padding: .4rem .25rem; border-radius: 8px;
background: rgba(255,255,255,.55); border: 1.5px solid rgba(0,0,0,.06);
cursor: pointer; font-family: inherit;
display: flex; flex-direction: column; align-items: center; gap: .1rem;
transition: all .12s;
}
.transport-btn:hover { border-color: var(--fjord); background: var(--fjord-l); }
.transport-btn.selected { border-color: var(--moss); background: var(--moss-l); }
.transport-btn .tb-emoji { font-size: 1.1rem; }
.transport-btn .tb-name { font-size: .55rem; font-weight: 700; }
.order-summary {
margin-top: .8rem; padding: .65rem .75rem;
background: rgba(0,0,0,.04); border-radius: 9px;
font-size: .68rem; line-height: 1.5;
}
.order-summary .os-row {
display: flex; justify-content: space-between;
font-variant-numeric: tabular-nums;
}
.order-summary .os-row strong { font-weight: 800; }
.os-good { color: var(--moss); }
.os-bad { color: var(--danger); }
.order-btn {
margin-top: .7rem; width: 100%;
padding: .65rem; border: none; border-radius: 9px;
background: var(--fjord); color: #fff;
font-weight: 800; font-size: .85rem; cursor: pointer;
font-family: inherit; transition: all .15s;
}
.order-btn:hover { background: var(--fjord-d); }
.order-btn:disabled { background: #c0c0c0; cursor: not-allowed; }
/* === EVENTS-STRIP (unten links neben dem Status) === */
.panel-events-strip {
position: fixed;
left: calc(var(--side-w) + var(--pad) * 2);
bottom: var(--pad);
width: 280px;
max-height: 90px;
padding: .35rem .55rem .45rem;
overflow: hidden;
cursor: pointer;
transition: max-height .38s cubic-bezier(.22,1,.36,1);
z-index: 12;
display: flex; flex-direction: column; gap: .25rem;
}
.panel-events-strip.open {
max-height: calc(100vh - var(--topbar-h) - 4 * var(--pad));
box-shadow: 0 18px 50px rgba(20,40,60,.28);
cursor: zoom-out;
}
.events-strip-header {
display: flex; justify-content: space-between; align-items: center;
font-size: .58rem; font-weight: 800; color: var(--fjord);
text-transform: uppercase; letter-spacing: .07em;
flex-shrink: 0;
}
.esh-toggle { transition: transform .35s ease-out; font-size: .65rem; color: var(--text3); }
.panel-events-strip.open .esh-toggle { transform: rotate(180deg); }
.events-strip-list {
overflow-y: auto;
flex: 1; min-height: 0;
}
.panel-events-strip:not(.open) .events-strip-list .event:not(:first-child) {
display: none;
}
.panel-events-strip:not(.open) .events-strip-list .event {
margin-bottom: 0;
}
.event {
padding:.3rem .45rem; border-radius:7px; margin-bottom:.25rem;
font-size:.65rem; line-height:1.3;
display:flex; gap:.3rem; align-items:flex-start;
}
.event-text { flex:1; }
.event-info { background:rgba(0,0,0,.05); color:var(--text2); }
.event-success { background:var(--moss-l); color:var(--moss); }
.event-warning { background:var(--sand-l); color:var(--sand); }
.event-danger { background:var(--coral-l); color:var(--danger); }
/* === TUTORIAL === */
.tutorial-overlay {
position:fixed; inset:0; background:rgba(15,30,40,.85);
backdrop-filter:blur(8px); display:flex; align-items:center;
justify-content:center; z-index:50; padding:1.5rem;
}
.tutorial-card {
background:#fff; border-radius:18px; padding:1.6rem 1.9rem;
max-width:520px; box-shadow:0 30px 80px rgba(0,0,0,.4);
}
.tutorial-card h3 { font-size:1.25rem; font-weight:800; margin-bottom:.6rem; color:var(--fjord); }
.tutorial-card p { font-size:.9rem; color:var(--text2); white-space:pre-line; margin-bottom:1rem; }
.progress-dots { display:flex; gap:.3rem; justify-content:center; margin:.8rem 0; }
.dot { width:8px; height:8px; border-radius:50%; background:#dadad0; }
.dot.active { background:var(--fjord); }
.tut-btn {
width:100%; padding:.75rem; background:var(--fjord); color:#fff;
border:none; border-radius:10px; font-weight:700; font-size:.95rem; cursor:pointer;
}
.tut-btn:hover { background:var(--fjord-d); }
/* === END SCREEN === */
.end-screen {
position:fixed; inset:0; background:rgba(15,30,40,.9);
backdrop-filter:blur(10px); display:flex; align-items:center;
justify-content:center; z-index:100; padding:2rem;
}
.end-card { background:#fff; border-radius:20px; padding:2rem 2.5rem; max-width:500px; text-align:center; box-shadow:0 30px 80px rgba(0,0,0,.4); }
.end-icon { font-size:4rem; margin-bottom:.5rem; }
.end-card h2 { font-size:1.8rem; font-weight:900; letter-spacing:-.02em; margin-bottom:.3rem; }
.end-card .end-summary { color:var(--text2); margin-bottom:1rem; }
.end-stats { display:grid; grid-template-columns:1fr 1fr; gap:.8rem; margin:1rem 0; }
.end-stat { background:#f7f6f3; border-radius:10px; padding:.8rem; }
.end-stat-val { font-size:1.4rem; font-weight:800; color:var(--fjord); }
.end-stat-lbl { font-size:.7rem; color:var(--text3); text-transform:uppercase; }
.end-goals { display:flex; flex-direction:column; gap:.3rem; margin:.8rem 0 1rem; text-align:left; }
.end-goal { display:flex; align-items:center; gap:.55rem; font-size:.82rem; padding:.35rem .55rem; border-radius:7px; background:#f7f6f3; }
.end-goal.done { color:var(--moss); background:var(--moss-l); }
.end-goal.fail { color:var(--danger); background:var(--coral-l); }
.end-goal-icon { font-weight:900; font-size:.95rem; width:1rem; text-align:center; }
</style>
</head>
<body>
<div id="canvas-wrap"></div>
<!-- TOP BAR -->
<nav class="floating topbar">
<a href="index.html" class="brand">
<img src="assets/img/logo.png" alt="">
Lieferketten-Planer*in
</a>
<div class="topbar-controls">
<div class="ctrl-group" title="Simulationsgeschwindigkeit">
<button class="icon-btn" data-speed="0" title="Pause"></button>
<button class="icon-btn active" data-speed="1" title="Normal (×1)">×1</button>
<button class="icon-btn" data-speed="2" title="Schnell (×2)">×2</button>
<button class="icon-btn" data-speed="4" title="Sehr schnell (×4)">×4</button>
</div>
<div class="topbar-sep"></div>
<button class="icon-btn" id="btn-save" title="Stand speichern">💾</button>
<button class="icon-btn" id="btn-load" title="Stand laden">📂</button>
<button class="icon-btn" id="btn-finish" title="Simulation beenden"></button>
<button class="icon-btn" id="btn-reset" title="Zurücksetzen">🔄</button>
<a class="icon-btn" href="index.html" title="Zurück zur Übersicht">🏠</a>
</div>
</nav>
<!-- LINKS: Status + Ziele -->
<aside class="floating panel-status">
<div class="panel-h">📊 Status</div>
<div id="resources"></div>
<div class="panel-h panel-h-sub">🎯 Ziele</div>
<div id="status-goals"></div>
</aside>
<!-- LINKS DANEBEN: Ereignisse-Strip -->
<aside class="floating panel-events-strip" id="events-strip">
<div class="events-strip-header">
<span>📰 Ereignisse</span>
<span class="esh-toggle"></span>
</div>
<div id="events" class="events-strip-list"></div>
</aside>
<!-- RECHTS: Bestell-Formular -->
<aside class="floating panel-order">
<div class="order-section">
<h4>🌾 Baumwolle</h4>
<div class="order-options" id="cotton-options"></div>
</div>
<div class="order-section">
<h4>🚚 Transport zur Näherei</h4>
<div class="transport-row" id="transport1-row"></div>
</div>
<div class="order-section">
<h4>🏭 Näherei</h4>
<div class="order-options" id="factory-options"></div>
</div>
<div class="order-section">
<h4>🚚 Transport nach Wien</h4>
<div class="transport-row" id="transport2-row"></div>
</div>
<div class="order-summary" id="order-summary"></div>
<button class="order-btn" id="order-btn" disabled>Bestellen</button>
</aside>
<!-- TUTORIAL -->
<div class="tutorial-overlay" id="tutorial">
<div class="tutorial-card">
<h3 id="tut-title"></h3>
<p id="tut-text"></p>
<div class="progress-dots" id="tut-dots"></div>
<button class="tut-btn" id="tut-next">Weiter →</button>
</div>
</div>
<div id="end-screen-host"></div>
<div id="citizen-event-host"></div>
<div id="info-overlay-host"></div>
<script type="module">
import {
LieferkettenGame, COTTON_SOURCES, FACTORIES, TRANSPORT_MODES, DEFAULT_CONFIG,
} from './src/sims/sim-10-lieferketten/game.ts'
import { LieferkettenRenderer } from './src/sims/sim-10-lieferketten/renderer.ts'
import { GameUI } from './src/ui/game-ui.ts'
import { installTooltips } from './src/ui/info-overlay.ts'
installTooltips()
// === Lehrer-Konfiguration via URL-Parameter ===
// ?config=<json> erlaubt der Lehrperson, die drei Hauptparameter zu setzen.
function readConfig() {
try {
const raw = new URLSearchParams(location.search).get('config')
if (raw) return JSON.parse(decodeURIComponent(raw))
} catch {}
return {}
}
const userConfig = readConfig()
const game = new LieferkettenGame(userConfig)
// === GameUI ohne Shop (wir bauen unser eigenes Bestell-Formular) ===
// Wir geben einen leeren shopItems-Array, damit GameUI nichts rendert.
const ui = new GameUI({
game,
Renderer: LieferkettenRenderer,
shopItems: [],
onBuy: () => false,
graphs: [],
saveKey: 'lieferketten-save',
yearOffset: 2025,
})
// === Bestell-Formular bauen ===
const filterByConfig = (list, allowed) => list.filter(x => allowed.includes(x.id))
const cottonAvailable = filterByConfig(COTTON_SOURCES, game.getConfig().enabledOptions.cotton)
const factoryAvailable = filterByConfig(FACTORIES, game.getConfig().enabledOptions.factory)
const transportAvailable = TRANSPORT_MODES.filter(t => game.getConfig().enabledOptions.transport.includes(t.id))
const currentOrder = {
cottonId: null,
factoryId: null,
transport1: null,
transport2: null,
}
function ratingClass(value, goodAbove, badBelow) {
if (value >= goodAbove) return 'oo-stat-good'
if (value < badBelow) return 'oo-stat-bad'
return ''
}
function renderCottonOptions() {
const el = document.getElementById('cotton-options')
el.innerHTML = cottonAvailable.map(c => `
<button class="order-option ${currentOrder.cottonId === c.id ? 'selected' : ''}" data-id="${c.id}">
<span class="oo-flag">${c.flag}</span>
<div class="oo-info">
<div class="oo-name">${c.country}</div>
<div class="oo-stats">
<span class="oo-stat">€${c.pricePerShirt.toFixed(2)}</span>
<span class="oo-stat ${ratingClass(-c.co2PerShirt, -1.5, -2.4)}">${c.co2PerShirt.toFixed(1)} kg CO₂</span>
<span class="oo-stat ${ratingClass(c.ethicsScore, 7, 5)}">⚖️ ${c.ethicsScore}</span>
</div>
</div>
</button>
`).join('')
el.querySelectorAll('.order-option').forEach(btn => {
btn.addEventListener('click', () => {
currentOrder.cottonId = btn.dataset.id
renderCottonOptions(); updatePreview()
})
})
}
function renderFactoryOptions() {
const el = document.getElementById('factory-options')
el.innerHTML = factoryAvailable.map(f => `
<button class="order-option ${currentOrder.factoryId === f.id ? 'selected' : ''}" data-id="${f.id}">
<span class="oo-flag">${f.flag}</span>
<div class="oo-info">
<div class="oo-name">${f.country}</div>
<div class="oo-stats">
<span class="oo-stat">€${f.pricePerShirt.toFixed(2)}</span>
<span class="oo-stat ${ratingClass(-f.co2PerShirt, -1.0, -1.5)}">${f.co2PerShirt.toFixed(1)} kg CO₂</span>
<span class="oo-stat ${ratingClass(f.ethicsScore, 7, 5)}">⚖️ ${f.ethicsScore}</span>
</div>
</div>
</button>
`).join('')
el.querySelectorAll('.order-option').forEach(btn => {
btn.addEventListener('click', () => {
currentOrder.factoryId = btn.dataset.id
renderFactoryOptions(); updatePreview()
})
})
}
function renderTransportRow(rowId, key) {
const el = document.getElementById(rowId)
el.innerHTML = transportAvailable.map(t => `
<button class="transport-btn ${currentOrder[key] === t.id ? 'selected' : ''}" data-id="${t.id}">
<span class="tb-emoji">${t.emoji}</span>
<span class="tb-name">${t.name.split(' ')[0]}</span>
</button>
`).join('')
el.querySelectorAll('.transport-btn').forEach(btn => {
btn.addEventListener('click', () => {
currentOrder[key] = btn.dataset.id
renderTransportRow(rowId, key); updatePreview()
})
})
}
function updatePreview() {
// Renderer-Vorschau aktualisieren
const r = ui.getRenderer()
if (r && typeof r.setPreviewOrder === 'function') {
r.setPreviewOrder(currentOrder)
}
// Order-Summary berechnen
const summary = document.getElementById('order-summary')
const btn = document.getElementById('order-btn')
const complete = currentOrder.cottonId && currentOrder.factoryId && currentOrder.transport1 && currentOrder.transport2
if (!complete) {
summary.innerHTML = '<div style="color:var(--text3);text-align:center;font-size:.7rem">Wähle alle 4 Stationen aus.</div>'
btn.disabled = true
return
}
// Vorschau-Berechnung lokal (mirror der placeOrder-Logik)
const c = COTTON_SOURCES.find(x => x.id === currentOrder.cottonId)
const f = FACTORIES.find(x => x.id === currentOrder.factoryId)
const t1 = TRANSPORT_MODES.find(x => x.id === currentOrder.transport1)
const t2 = TRANSPORT_MODES.find(x => x.id === currentOrder.transport2)
// Sehr grobe Schätzung — wir nutzen die Distanz-Mittelwerte (nicht die Effekte)
const dist1 = 5 // ~5000 km Schätzwert für Vorschau
const dist2 = 3 // ~3000 km Schätzwert
const t1Cost = t1.costPer1000km * dist1
const t2Cost = t2.costPer1000km * dist2
const t1CO2 = t1.co2Per1000km * dist1
const t2CO2 = t2.co2Per1000km * dist2
const costPerShirt = c.pricePerShirt + f.pricePerShirt + t1Cost + t2Cost
const co2PerShirt = c.co2PerShirt + f.co2PerShirt + t1CO2 + t2CO2
const ethics = (c.ethicsScore + f.ethicsScore) / 2
const profitPerShirt = 12 - costPerShirt
const profitMio = (5000 * profitPerShirt) / 1_000_000
const profitClass = profitMio >= 0 ? 'os-good' : 'os-bad'
const co2Class = co2PerShirt < 6 ? 'os-good' : 'os-bad'
const ethicsClass = ethics >= 5 ? 'os-good' : 'os-bad'
summary.innerHTML = `
<div class="os-row"><span>Kosten/Stück</span><strong>€${costPerShirt.toFixed(2)}</strong></div>
<div class="os-row"><span>Gewinn/Charge</span><strong class="${profitClass}">${profitMio >= 0 ? '+' : ''}${profitMio.toFixed(2)} Mio €</strong></div>
<div class="os-row"><span>CO₂/Stück</span><strong class="${co2Class}">${co2PerShirt.toFixed(1)} kg</strong></div>
<div class="os-row"><span>Ø Ethik</span><strong class="${ethicsClass}">${ethics.toFixed(1)} / 10</strong></div>
`
btn.disabled = false
}
document.getElementById('order-btn').addEventListener('click', () => {
if (!currentOrder.cottonId || !currentOrder.factoryId || !currentOrder.transport1 || !currentOrder.transport2) return
game.placeOrder({ ...currentOrder })
// Sprite-Animation auf der Karte
const r = ui.getRenderer()
if (r && typeof r.animateOrder === 'function') r.animateOrder(currentOrder)
})
// Events-Strip toggle
const eventsStrip = document.getElementById('events-strip')
eventsStrip.addEventListener('click', (ev) => {
ev.stopPropagation()
eventsStrip.classList.toggle('open')
})
document.addEventListener('click', (ev) => {
if (!eventsStrip.classList.contains('open')) return
if (eventsStrip.contains(ev.target)) return
eventsStrip.classList.remove('open')
})
// Initial render
renderCottonOptions()
renderFactoryOptions()
renderTransportRow('transport1-row', 'transport1')
renderTransportRow('transport2-row', 'transport2')
updatePreview()
</script>
</body>
</html>
@@ -1,520 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Forscher*in im Regenwald</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="assets/fonts/inter.css">
<style>
*, *::before, *::after { margin:0; padding:0; box-sizing:border-box; }
:root {
--text: #1a1a1a; --text2: #4a4a4a; --text3: #8a8a8a;
--fjord: #4a7c8a; --fjord-l: #dae8ec; --fjord-d: #3a6470;
--moss: #5a8a5e; --moss-l: #dceadd;
--sand: #c4a35a; --sand-l: #f2eacc;
}
html, body { height:100%; overflow:hidden; }
body { font-family:'Inter',system-ui,sans-serif; color:var(--text); background: #2a5a3a; overflow: hidden; }
/* === FLUSS-KARTE (scrollender Hintergrund) === */
#river-scene {
position: fixed; inset: -200vh 0; z-index: 0;
overflow: visible;
/* Der Gradient — 3x viewport height to prevent white edges */
background: linear-gradient(0deg, #a8d8c8 0%, #5a9a6a 30%, #3a7a4a 60%, #2a5a3a 80%, #1a4a2a 100%);
background-size: 100% 300vh;
background-position: center bottom;
}
/* Flussbett — ein vertikaler Streifen in der Mitte */
#river-bed {
position: absolute;
left: 50%; transform: translateX(-50%);
width: 140px;
top: 0; bottom: 0;
background: linear-gradient(180deg, rgba(60,120,160,.5) 0%, rgba(40,90,130,.65) 100%);
border-left: 2px solid rgba(40,80,120,.3);
border-right: 2px solid rgba(40,80,120,.3);
border-radius: 10px;
}
/* Wellen-Effekt (CSS, keine Sprites) */
#river-bed::before {
content: '';
position: absolute; inset: 0;
background: repeating-linear-gradient(
0deg,
transparent 0px,
transparent 28px,
rgba(255,255,255,.12) 30px,
transparent 32px
);
animation: wave 3s linear infinite;
}
@keyframes wave { from { background-position-y: 0; } to { background-position-y: 60px; } }
/* === UFER-BÄUME (einfache Emoji-Reihen links und rechts) === */
.tree-row {
position: absolute; top: 0; bottom: 0;
width: 80px;
display: flex; flex-direction: column; gap: 35px;
padding-top: 20px;
font-size: 1.6rem; line-height: 1;
overflow: hidden;
pointer-events: none;
}
.tree-row.left { left: calc(50% - 140px); text-align: right; }
.tree-row.right { right: calc(50% - 140px); text-align: left; }
/* === BOOT === */
#boat {
position: fixed;
left: 50%; bottom: 38%;
transform: translateX(-50%);
font-size: 2.6rem;
z-index: 10;
transition: bottom .8s cubic-bezier(.22,1,.36,1);
filter: drop-shadow(0 4px 8px rgba(0,0,0,.25));
pointer-events: none;
}
/* === ENTDECKUNGS-MARKER === */
.discovery-marker {
position: absolute;
left: 50%;
transform: translateX(-50%);
z-index: 8;
cursor: pointer;
transition: all .25s cubic-bezier(.22,1,.36,1);
}
.dm-bubble {
display: flex; align-items: center; justify-content: center;
width: 52px; height: 52px;
border-radius: 50%;
background: rgba(255,255,255,.85);
box-shadow: 0 4px 16px rgba(0,40,30,.22);
border: 2.5px solid rgba(255,255,255,.8);
font-size: 1.7rem;
transition: all .2s;
}
.dm-bubble:hover { transform: scale(1.2); box-shadow: 0 6px 24px rgba(0,40,30,.35); }
.dm-bubble.found { border-color: var(--moss); background: var(--moss-l); }
.dm-bubble.mystery {
background: rgba(255,255,255,.5);
border: 2.5px dashed rgba(0,0,0,.2);
font-size: 1.4rem; color: var(--text3);
}
.dm-name {
text-align: center;
font-size: .62rem; font-weight: 700;
color: #fff;
text-shadow: 0 1px 4px rgba(0,0,0,.5);
margin-top: .2rem;
white-space: nowrap;
}
/* === INFO-KARTE (erscheint bei Klick auf ein Tier) === */
.info-overlay {
position: fixed; inset: 0; z-index: 50;
background: rgba(15,35,25,.75); backdrop-filter: blur(8px);
display: flex; align-items: center; justify-content: center;
padding: 1.5rem;
animation: fadein .25s ease-out;
}
@keyframes fadein { from { opacity:0; } to { opacity:1; } }
.info-card {
background: #fff; border-radius: 20px;
padding: 1.8rem 2rem; max-width: 480px; width: 100%;
box-shadow: 0 30px 80px rgba(0,0,0,.4);
animation: cardpop .3s cubic-bezier(.22,1,.36,1);
}
@keyframes cardpop {
from { transform: scale(.9) translateY(15px); opacity:0; }
to { transform: scale(1) translateY(0); opacity:1; }
}
.info-card .ic-emoji { font-size: 3.5rem; text-align: center; margin-bottom: .5rem; }
.info-card h3 { font-size: 1.3rem; font-weight: 800; color: var(--fjord); margin-bottom: .5rem; text-align: center; }
.info-card .ic-zone {
text-align: center; font-size: .62rem; font-weight: 700;
color: var(--moss); text-transform: uppercase; letter-spacing: .06em;
margin-bottom: .8rem;
}
.info-card p { font-size: .95rem; color: var(--text2); line-height: 1.6; margin-bottom: .7rem; }
.info-card .ic-wow {
background: var(--sand-l); border-left: 3px solid var(--sand);
padding: .7rem .9rem; border-radius: 0 8px 8px 0;
font-size: .85rem; color: var(--text2); margin-bottom: .9rem;
}
.info-card .ic-wow::before { content: '🤯 '; }
.info-card .ic-btn {
width: 100%; padding: .7rem; border: none; border-radius: 10px;
background: var(--moss); color: #fff;
font-weight: 700; font-size: .9rem; cursor: pointer;
font-family: inherit;
}
.info-card .ic-btn:hover { background: #4a7a4e; }
/* === TOPBAR (sehr schlank) === */
.topbar {
position: fixed; top: 0; left: 0; right: 0; z-index: 20;
padding: .3rem .8rem;
display: flex; justify-content: space-between; align-items: center;
background: rgba(255,255,255,.75);
backdrop-filter: blur(10px);
border-bottom: 1px solid rgba(0,0,0,.08);
}
.topbar .brand {
display: flex; align-items: center; gap: .45rem;
font-weight: 800; font-size: .85rem; color: var(--fjord);
text-decoration: none;
}
.topbar .brand img { width: 22px; height: 22px; border-radius: 5px; }
/* === SAMMELHEFT (rechts oben) === */
.sammelheft {
position: fixed; top: 3.2rem; right: .65rem; z-index: 15;
background: rgba(255,255,255,.88);
backdrop-filter: blur(12px);
border: 1px solid rgba(255,255,255,.6);
box-shadow: 0 8px 28px rgba(20,40,60,.18);
border-radius: 14px;
padding: .6rem .75rem;
width: 200px;
}
.sammelheft h4 {
font-size: .62rem; font-weight: 800; color: var(--fjord);
text-transform: uppercase; letter-spacing: .07em;
margin-bottom: .4rem;
}
.sh-grid {
display: grid;
grid-template-columns: repeat(5, 1fr);
gap: .3rem;
}
.sh-slot {
width: 32px; height: 32px;
border-radius: 7px;
display: flex; align-items: center; justify-content: center;
font-size: 1.15rem;
background: rgba(0,0,0,.06);
border: 1.5px solid rgba(0,0,0,.06);
transition: all .2s;
}
.sh-slot.found { background: var(--moss-l); border-color: var(--moss); }
.sh-slot.empty { color: var(--text3); font-size: .85rem; }
.sh-progress {
margin-top: .45rem;
font-size: .62rem; font-weight: 700; color: var(--text2);
text-align: center;
}
.sh-bar { height: 4px; background: rgba(0,0,0,.08); border-radius: 2px; margin-top: .2rem; overflow: hidden; }
.sh-bar-fill { height: 100%; background: var(--moss); border-radius: 2px; transition: width .4s; }
/* === ZONEN-ANZEIGE (unten links, zeigt aktuelle Zone) === */
.zone-badge {
position: fixed; bottom: .8rem; left: .8rem; z-index: 15;
background: rgba(255,255,255,.82);
backdrop-filter: blur(10px);
border-radius: 12px; padding: .5rem .8rem;
box-shadow: 0 4px 16px rgba(0,0,0,.12);
font-size: .72rem; font-weight: 700; color: var(--text);
}
.zone-badge .zb-emoji { font-size: 1.1rem; margin-right: .3rem; }
.zone-badge .zb-name { color: var(--moss); }
/* === STEUERUNGS-HINT (unten mitte) === */
.controls-hint {
position: fixed; bottom: .8rem; left: 50%; transform: translateX(-50%);
z-index: 15;
background: rgba(255,255,255,.75);
backdrop-filter: blur(10px);
border-radius: 10px; padding: .4rem .8rem;
box-shadow: 0 4px 12px rgba(0,0,0,.1);
font-size: .65rem; color: var(--text2); font-weight: 600;
}
.controls-hint kbd {
display: inline-block; padding: 1px 5px;
background: rgba(0,0,0,.08); border: 1px solid rgba(0,0,0,.12);
border-radius: 3px; font-size: .62rem; font-weight: 800;
font-family: ui-monospace, monospace;
}
/* === GLÜCKWUNSCH-OVERLAY === */
.congrats-overlay {
position: fixed; inset: 0; z-index: 60;
background: rgba(15,35,25,.85); backdrop-filter: blur(10px);
display: flex; align-items: center; justify-content: center;
padding: 1.5rem;
}
.congrats-card {
background: #fff; border-radius: 20px; padding: 2rem 2.5rem;
max-width: 480px; text-align: center;
box-shadow: 0 30px 80px rgba(0,0,0,.4);
}
.congrats-card .cc-emoji { font-size: 4rem; margin-bottom: .5rem; }
.congrats-card h2 { font-size: 1.6rem; font-weight: 900; color: var(--fjord); margin-bottom: .5rem; }
.congrats-card p { font-size: .92rem; color: var(--text2); line-height: 1.6; margin-bottom: 1rem; }
.congrats-card .cc-stat { font-size: 1.1rem; font-weight: 800; color: var(--moss); margin-bottom: 1rem; }
.congrats-card .ic-btn { width: 100%; }
</style>
</head>
<body>
<!-- TOPBAR -->
<nav class="topbar">
<a href="index.html" class="brand">
<img src="assets/img/logo.png" alt="">
Forscher*in im Regenwald 🌴
</a>
<a href="index.html" class="brand" style="font-size:.7rem;opacity:.6;">← Zurück</a>
</nav>
<!-- SAMMELHEFT -->
<div class="sammelheft" id="sammelheft">
<h4>📔 Sammelheft</h4>
<div class="sh-grid" id="sh-grid"></div>
<div class="sh-progress" id="sh-progress">0 von 15 entdeckt</div>
<div class="sh-bar"><div class="sh-bar-fill" id="sh-bar-fill" style="width:0%"></div></div>
</div>
<!-- ZONEN-ANZEIGE -->
<div class="zone-badge" id="zone-badge">
<span class="zb-emoji">🏝</span>
<span class="zb-name">Flussmündung</span>
</div>
<!-- STEUERUNGS-HINT -->
<div class="controls-hint">
<kbd></kbd> flussaufwärts · <kbd></kbd> flussabwärts · Klick auf ein Tier zum Entdecken
</div>
<!-- FLUSS-SZENE -->
<div id="river-scene">
<div id="river-bed"></div>
<div class="tree-row left" id="trees-left"></div>
<div class="tree-row right" id="trees-right"></div>
<!-- Entdeckungs-Marker werden hier per JS eingefügt -->
</div>
<!-- BOOT -->
<div id="boat">🛶</div>
<!-- INFO-KARTE HOST -->
<div id="info-host"></div>
<!-- GLÜCKWUNSCH HOST -->
<div id="congrats-host"></div>
<script type="module">
import { DISCOVERIES, ZONES } from './src/sims/sim-11-regenwald/data.ts'
// ===================================================================
// STATE
// ===================================================================
const SAVE_KEY = 'regenwald-discovered'
let discovered = new Set()
try {
const saved = JSON.parse(localStorage.getItem(SAVE_KEY) || '[]')
if (Array.isArray(saved)) discovered = new Set(saved)
} catch {}
// Scroll-Position: 0 = Flussmündung (unten), 100 = Bergregenwald (oben)
let scrollPos = 0
const SCROLL_SPEED = 0.6
const SCENE_HEIGHT_VH = 350 // virtuelle Höhe der Szene in vh-Einheiten
function save() {
localStorage.setItem(SAVE_KEY, JSON.stringify([...discovered]))
}
// ===================================================================
// BÄUME AM UFER (deko, statisch)
// ===================================================================
function buildTrees() {
const treeEmojis = ['🌴', '🌳', '🌿', '🎋', '🌲']
const count = 35
for (const side of ['left', 'right']) {
const el = document.getElementById(`trees-${side}`)
let html = ''
for (let i = 0; i < count; i++) {
const emoji = treeEmojis[Math.floor(Math.random() * treeEmojis.length)]
const offset = side === 'left'
? `padding-right:${Math.random() * 30}px`
: `padding-left:${Math.random() * 30}px`
html += `<div style="${offset}">${emoji}</div>`
}
el.innerHTML = html
}
}
buildTrees()
// ===================================================================
// ENTDECKUNGS-MARKER
// ===================================================================
const scene = document.getElementById('river-scene')
const markerEls = []
for (const d of DISCOVERIES) {
const marker = document.createElement('div')
marker.className = 'discovery-marker'
marker.dataset.id = d.id
// Position: 0 = unten (100vh), 100 = oben (0vh)
// Wir setzen die Position relativ zur Szene-Höhe (SCENE_HEIGHT_VH)
const topPct = (1 - d.position / 100) * SCENE_HEIGHT_VH
marker.style.top = `${topPct}vh`
// Leicht links/rechts versetzen (abwechselnd)
const xOff = (DISCOVERIES.indexOf(d) % 2 === 0 ? -45 : 45)
marker.style.marginLeft = `${xOff}px`
const isFound = discovered.has(d.id)
marker.innerHTML = `
<div class="dm-bubble ${isFound ? 'found' : 'mystery'}">
${isFound ? d.emoji : '❓'}
</div>
<div class="dm-name">${isFound ? d.name : '???'}</div>
`
marker.addEventListener('click', () => showInfo(d))
scene.appendChild(marker)
markerEls.push({ marker, data: d })
}
// ===================================================================
// SAMMELHEFT
// ===================================================================
function renderSammelheft() {
const grid = document.getElementById('sh-grid')
grid.innerHTML = DISCOVERIES.map(d => {
const found = discovered.has(d.id)
return `<div class="sh-slot ${found ? 'found' : 'empty'}" title="${found ? d.name : '???'}">
${found ? d.emoji : '?'}
</div>`
}).join('')
const count = discovered.size
document.getElementById('sh-progress').textContent = `${count} von ${DISCOVERIES.length} entdeckt`
document.getElementById('sh-bar-fill').style.width = `${(count / DISCOVERIES.length) * 100}%`
}
renderSammelheft()
// ===================================================================
// ZONEN-BADGE
// ===================================================================
function updateZoneBadge() {
let zone = ZONES[0]
if (scrollPos > 33) zone = ZONES[1]
if (scrollPos > 66) zone = ZONES[2]
const badge = document.getElementById('zone-badge')
badge.innerHTML = `<span class="zb-emoji">${zone.emoji}</span> <span class="zb-name">${zone.name}</span> — ${zone.description}`
}
updateZoneBadge()
// ===================================================================
// SCROLL-MECHANIK (Pfeiltasten)
// ===================================================================
const keysDown = new Set()
window.addEventListener('keydown', (e) => {
if (e.key === 'ArrowUp' || e.key === 'ArrowDown') {
e.preventDefault()
keysDown.add(e.key)
}
})
window.addEventListener('keyup', (e) => keysDown.delete(e.key))
// Mausrad scrollt auch
window.addEventListener('wheel', (e) => {
e.preventDefault()
scrollPos = Math.max(0, Math.min(100, scrollPos + (e.deltaY > 0 ? -SCROLL_SPEED * 2 : SCROLL_SPEED * 2)))
applyScroll()
}, { passive: false })
function applyScroll() {
// Szene verschieben: 0 = Boden, 100 = Spitze
const translateY = scrollPos / 100 * (SCENE_HEIGHT_VH - 100)
scene.style.transform = `translateY(${translateY}vh)`
// Hintergrund-Gradient anpassen
const zone = scrollPos < 33 ? 0 : scrollPos < 66 ? 1 : 2
const z = ZONES[zone]
scene.style.background = `linear-gradient(0deg, ${z.bgFrom} 0%, ${z.bgTo} 100%)`
updateZoneBadge()
}
// rAF-Loop für Pfeiltasten-Scroll
function scrollLoop() {
if (keysDown.has('ArrowUp')) scrollPos = Math.min(100, scrollPos + SCROLL_SPEED)
if (keysDown.has('ArrowDown')) scrollPos = Math.max(0, scrollPos - SCROLL_SPEED)
if (keysDown.size > 0) applyScroll()
requestAnimationFrame(scrollLoop)
}
requestAnimationFrame(scrollLoop)
// ===================================================================
// INFO-KARTE
// ===================================================================
function showInfo(d) {
// Entdeckung registrieren
const wasNew = !discovered.has(d.id)
discovered.add(d.id)
save()
// Marker aktualisieren
const mel = markerEls.find(m => m.data.id === d.id)
if (mel) {
const bubble = mel.marker.querySelector('.dm-bubble')
bubble.className = 'dm-bubble found'
bubble.textContent = d.emoji
mel.marker.querySelector('.dm-name').textContent = d.name
}
renderSammelheft()
// Info-Overlay
const host = document.getElementById('info-host')
const zone = ZONES.find(z => z.id === d.zone)
host.innerHTML = `
<div class="info-overlay" id="info-bg">
<div class="info-card">
<div class="ic-emoji">${d.emoji}</div>
<h3>${d.name}</h3>
<div class="ic-zone">${zone?.emoji || ''} ${zone?.name || d.zone}</div>
<p>${d.fact}</p>
${d.wow ? `<div class="ic-wow">${d.wow}</div>` : ''}
<button class="ic-btn" id="info-close">
${wasNew ? '✅ Entdeckt! Weiter' : 'Verstanden ✓'}
</button>
</div>
</div>
`
document.getElementById('info-close')?.addEventListener('click', closeInfo)
document.getElementById('info-bg')?.addEventListener('click', (e) => {
if (e.target.id === 'info-bg') closeInfo()
})
// Prüfen ob alle gefunden
if (discovered.size === DISCOVERIES.length) {
setTimeout(showCongrats, 800)
}
}
function closeInfo() {
document.getElementById('info-host').innerHTML = ''
}
// ===================================================================
// GLÜCKWUNSCH
// ===================================================================
function showCongrats() {
const host = document.getElementById('congrats-host')
host.innerHTML = `
<div class="congrats-overlay">
<div class="congrats-card">
<div class="cc-emoji">🏆🌴</div>
<h2>Alle Tiere entdeckt!</h2>
<div class="cc-stat">${DISCOVERIES.length} von ${DISCOVERIES.length} gefunden</div>
<p>Du hast den ganzen Regenwald erforscht — von der Flussmündung bis zum Bergregenwald.</p>
<p>Aber vergiss nicht: Jedes Jahr verschwindet eine Regenwald-Fläche so groß wie die Schweiz. Was wir kennen, können wir schützen. 🌍</p>
<button class="ic-btn" onclick="this.closest('.congrats-overlay').remove()">Nochmal erkunden</button>
</div>
</div>
`
}
</script>
</body>
</html>
@@ -1,300 +0,0 @@
<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>GeoGraSim — Stadt & Raumplanung</title>
<link rel="icon" type="image/png" href="favicon-96x96.png" sizes="96x96"><link rel="icon" type="image/svg+xml" href="favicon.svg">
<link rel="stylesheet" href="assets/fonts/inter.css">
<style>
*{margin:0;padding:0;box-sizing:border-box}
body{font-family:'Inter',sans-serif;background:#f0efe8;color:#1a1a1a;display:flex;height:100vh;overflow:hidden}
.sidebar{width:155px;background:#fff;border-right:1px solid rgba(0,0,0,.06);display:flex;flex-direction:column;overflow-y:auto}
.sidebar-section{padding:6px}
.sidebar h3{font-size:8px;color:#4a7c8a;text-transform:uppercase;letter-spacing:.05em;margin-bottom:3px;padding:0 4px}
.tb{display:flex;align-items:center;gap:3px;padding:3px 4px;border:1.5px solid transparent;border-radius:4px;cursor:pointer;font-size:8px;font-weight:600;margin-bottom:1px;transition:all .1s}
.tb:hover{border-color:#4a7c8a;background:#f0f6f8}
.tb.on{border-color:#4a7c8a;background:#4a7c8a;color:#fff}
.tb.off{opacity:.2;pointer-events:none}
.tb .te{font-size:13px}
.tb .tc{margin-left:auto;font-size:7px;color:#c4a35a}
.center{flex:1;display:flex;flex-direction:column;min-width:0}
.topbar{display:flex;align-items:center;gap:6px;padding:4px 8px;background:#fff;border-bottom:1px solid rgba(0,0,0,.05);flex-shrink:0}
.topbar .stat{font-size:10px;font-weight:700}
.topbar .gold{color:#c4a35a}
.topbar .rnd{font-size:9px;color:#4a7c8a;background:#dae8ec;padding:2px 6px;border-radius:4px;font-weight:700;margin-left:auto}
.topbar .btn{padding:2px 8px;border:none;border-radius:4px;background:#4a7c8a;color:#fff;font-size:9px;font-weight:700;cursor:pointer}
.canvas-area{flex:1;display:flex;align-items:center;justify-content:center;background:#c8d0b8;overflow:hidden}
.canvas-area canvas{max-width:100%;max-height:100%}
.right{width:155px;background:#fff;border-left:1px solid rgba(0,0,0,.06);display:flex;flex-direction:column;overflow-y:auto;padding:6px}
.right h3{font-size:8px;color:#4a7c8a;text-transform:uppercase;letter-spacing:.05em;margin-bottom:3px}
.param{display:flex;align-items:center;gap:3px;padding:2px 0;border-bottom:1px solid rgba(0,0,0,.02)}
.param:last-child{border:none}
.param-i{font-size:10px;width:14px;text-align:center}
.param-inf{flex:1}
.param-n{font-size:7px;color:#8a8a8a}
.param-bar{height:3px;background:#e8e5dc;border-radius:1.5px;margin-top:1px;overflow:hidden}
.param-bar-f{height:100%;border-radius:1.5px;transition:width .4s}
.param-v{font-size:8px;font-weight:700;min-width:14px;text-align:right}
.msg{font-size:7px;padding:2px 4px;border-radius:3px;margin-bottom:1px;background:#dae8ec;color:#3a6470;line-height:1.2}
.msg.warn{background:#f2ddd8;color:#c07a6b}
.msg.good{background:#dceadd;color:#5a8a5e}
.ov{position:fixed;inset:0;background:rgba(0,0,0,.4);display:flex;align-items:center;justify-content:center;z-index:100}
.ov-c{background:#fff;border-radius:12px;padding:1.2rem;max-width:360px;width:90%;text-align:center}
.ov-c h2{font-size:.9rem;font-weight:800;margin-bottom:.15rem}
.ov-c p{font-size:.7rem;color:#4a4a4a;margin-bottom:.4rem}
.ov-btn{padding:.3rem .8rem;border:none;border-radius:5px;background:#4a7c8a;color:#fff;font-size:.7rem;font-weight:700;cursor:pointer}
.hidden{display:none}
@media(max-width:700px){.sidebar,.right{display:none}.center{width:100%}}
</style>
</head>
<body>
<div class="sidebar">
<div class="sidebar-section">
<h3>Straßen</h3>
<div id="road-tools"></div>
</div>
<div class="sidebar-section">
<h3>Gebäude</h3>
<div id="building-tools"></div>
</div>
<div class="sidebar-section">
<h3>Natur</h3>
<div id="nature-tools"></div>
</div>
</div>
<div class="center">
<div class="topbar">
<span class="stat gold">💰 <span id="h-bud">50</span></span>
<span class="stat" style="font-size:8px;color:#5a8a5e" id="h-inc"></span>
<span class="rnd" id="h-rnd">1/10</span>
<button class="btn" id="btn-next">▶ Runde</button>
</div>
<div class="canvas-area"><canvas id="cv"></canvas></div>
</div>
<div class="right">
<h3>Kennwerte</h3>
<div id="params"></div>
<h3 style="margin-top:6px">Nachrichten</h3>
<div id="msgs"></div>
</div>
<div class="ov" id="ov-intro">
<div class="ov-c">
<h2>🏘️ Stadt & Raumplanung</h2>
<p>Baue eine Siedlung! Wähle links Kacheln und klicke ins Raster. Klicke oben-links/rechts auf platzierte Kacheln zum Drehen. Jede Runde bekommst du neues Budget.</p>
<button class="ov-btn" id="btn-go">Los geht's!</button>
</div>
</div>
<div class="ov hidden" id="ov-end">
<div class="ov-c"><h2 id="end-t"></h2><p id="end-p"></p><button class="ov-btn" id="btn-again">Nochmal</button></div>
</div>
<script>
var COLS=10, ROWS=10, TS=60
var GREEN='#b8ccaa', ROAD='#2e2e2e', WHITE='#fff'
// === ALLE KACHEL-TYPEN ===
// cat: road/building/nature, conn: [N,E,S,W], emoji: fuer Gebaeude
var TILES = [
// Strassen (cat=0)
{n:'Gerade │', cat:0, conn:[1,0,1,0], cost:2, emoji:'', eff:{}},
{n:'Gerade ─', cat:0, conn:[0,1,0,1], cost:2, emoji:'', eff:{}},
{n:'Kurve ╯', cat:0, conn:[1,1,0,0], cost:2, emoji:'', eff:{}},
{n:'Kurve ╮', cat:0, conn:[0,1,1,0], cost:2, emoji:'', eff:{}},
{n:'Kurve ╭', cat:0, conn:[0,0,1,1], cost:2, emoji:'', eff:{}},
{n:'Kurve ╰', cat:0, conn:[1,0,0,1], cost:2, emoji:'', eff:{}},
{n:'T ┴', cat:0, conn:[1,1,0,1], cost:3, emoji:'', eff:{}},
{n:'T ├', cat:0, conn:[1,1,1,0], cost:3, emoji:'', eff:{}},
{n:'T ┬', cat:0, conn:[0,1,1,1], cost:3, emoji:'', eff:{}},
{n:'T ┤', cat:0, conn:[1,0,1,1], cost:3, emoji:'', eff:{}},
{n:'Kreuzung', cat:0, conn:[1,1,1,1], cost:4, emoji:'', eff:{}},
// Gebaeude (cat=1) — mit Strassen + Emojis
{n:'Wohngebiet', cat:1, conn:[1,0,1,0], cost:6, emoji:'🏠🏡🏠', emojis:[{e:'🏠',x:-0.32,y:-0.2,s:0.15},{e:'🏡',x:0.32,y:0,s:0.15},{e:'🏠',x:-0.3,y:0.2,s:0.13},{e:'🏠',x:0.3,y:0.25,s:0.12}], eff:{eco:2,sat:2,env:-1,traf:1}},
{n:'Laden', cat:1, conn:[1,0,1,0], cost:7, emoji:'🏪', emojis:[{e:'🏪',x:0.3,y:0,s:0.22}], eff:{eco:4,sat:2,env:-1,traf:2,sup:5}},
{n:'Schule', cat:1, conn:[0,1,0,1], cost:9, emoji:'🏫', emojis:[{e:'🏫',x:0,y:-0.25,s:0.22}], eff:{eco:1,sat:5,traf:1,sup:4}},
{n:'Kirche', cat:1, conn:[0,0,1,0], cost:8, emoji:'⛪', emojis:[{e:'⛪',x:0,y:-0.05,s:0.4}], eff:{eco:1,sat:4,env:1,sup:2}},
{n:'Fabrik', cat:1, conn:[0,0,1,0], cost:8, emoji:'🏭', emojis:[{e:'🏭',x:0,y:-0.05,s:0.35}], eff:{eco:6,sat:-3,env:-6,traf:4}},
{n:'Spital', cat:1, conn:[1,0,0,0], cost:11,emoji:'🏥', emojis:[{e:'🏥',x:0,y:0.1,s:0.28},{e:'🚑',x:0,y:0.35,s:0.12}], eff:{eco:2,sat:5,traf:2,sup:5}},
{n:'Feuerwehr', cat:1, conn:[0,0,1,0], cost:8, emoji:'🚒', emojis:[{e:'🏠',x:0,y:-0.15,s:0.25},{e:'🚒',x:-0.15,y:0.2,s:0.18},{e:'🚒',x:0.15,y:0.2,s:0.18}], eff:{eco:1,sat:3,sup:3}},
{n:'Polizei', cat:1, conn:[1,0,0,0], cost:7, emoji:'🚔', emojis:[{e:'🏢',x:0,y:0.1,s:0.25},{e:'🚔',x:0,y:0.32,s:0.15}], eff:{eco:1,sat:3,sup:2}},
{n:'Supermarkt', cat:1, conn:[1,0,1,0], cost:9, emoji:'🏪', emojis:[{e:'🏪',x:0.3,y:-0.1,s:0.22},{e:'🚗',x:0.28,y:0.25,s:0.1},{e:'🚙',x:0.36,y:0.15,s:0.1}], eff:{eco:5,sat:3,env:-2,traf:3,sup:8}},
{n:'Hochhäuser', cat:1, conn:[1,0,1,0], cost:10,emoji:'🏢', emojis:[{e:'🏢',x:0.25,y:-0.15,s:0.16},{e:'🏢',x:0.33,y:-0.15,s:0.16},{e:'🏢',x:0.25,y:0.12,s:0.16},{e:'🏢',x:0.33,y:0.12,s:0.16}], eff:{eco:4,env:-2,traf:3}},
{n:'Rathaus', cat:1, conn:[0,0,1,0], cost:12,emoji:'🏛️', emojis:[{e:'🏛️',x:0,y:-0.05,s:0.35}], eff:{eco:3,sat:4,sup:3}},
{n:'Tankstelle', cat:1, conn:[1,0,1,0], cost:5, emoji:'⛽', emojis:[{e:'⛽',x:0.3,y:-0.15,s:0.14},{e:'⛽',x:0.3,y:0,s:0.14},{e:'⛽',x:0.3,y:0.15,s:0.14},{e:'🚗',x:0.38,y:0.05,s:0.1}], eff:{eco:2,env:-2,traf:1}},
{n:'Bauernhof', cat:1, conn:[0,1,0,0], cost:5, emoji:'🌾', emojis:[{e:'🏠',x:0,y:0,s:0.22},{e:'🌾',x:-0.3,y:-0.25,s:0.1},{e:'🌾',x:-0.15,y:-0.25,s:0.1},{e:'🌾',x:0,y:-0.25,s:0.1},{e:'🌾',x:0.15,y:-0.25,s:0.1},{e:'🐄',x:-0.2,y:0.25,s:0.13}], eff:{eco:3,sat:1,env:2,sup:3}},
// Natur (cat=2)
{n:'Park', cat:2, conn:[1,0,0,0], cost:4, emoji:'🌳', emojis:[{e:'🌳',x:-0.25,y:0.05,s:0.14},{e:'🌳',x:-0.05,y:0.05,s:0.14},{e:'🌳',x:0.15,y:0.05,s:0.14},{e:'🌳',x:0.3,y:0.05,s:0.13},{e:'🌷',x:-0.2,y:0.3,s:0.07},{e:'🌷',x:0,y:0.3,s:0.07},{e:'🌷',x:0.2,y:0.3,s:0.07}], eff:{sat:4,env:6,sup:1}},
{n:'Spielplatz', cat:2, conn:[1,0,0,0], cost:4, emoji:'🛝', emojis:[{e:'🛝',x:-0.15,y:0.08,s:0.18},{e:'🎠',x:0.18,y:0.08,s:0.15},{e:'⚽',x:0,y:0.3,s:0.08},{e:'🌳',x:-0.35,y:0.3,s:0.1},{e:'🌳',x:0.35,y:0.3,s:0.1}], eff:{sat:5,env:3}},
]
var grid = []
for(var r=0;r<ROWS;r++){grid[r]=[];for(var c=0;c<COLS;c++)grid[r][c]=null}
// Start: ein paar Strassen + 2 Haeuser
grid[4][4]={t:1,r:0};grid[4][5]={t:1,r:0};grid[4][6]={t:1,r:0} // Gerade E-W
grid[3][5]={t:11,r:0} // Wohngebiet
var sel=-1, budget=50, round=1, maxRounds=10, income=6, gameOver=false
var scores={eco:40,sat:40,env:55,traf:15,sup:15,reach:25}
var messages=[{text:'Willkommen! Baue Straßen und Gebäude.',type:''}]
function rotConn(c,n){var r=c.slice();for(var i=0;i<n;i++)r=[r[3],r[0],r[1],r[2]];return r}
// === DRAW TILE ===
var cv=document.getElementById('cv'), ctx=cv.getContext('2d')
cv.width=COLS*TS;cv.height=ROWS*TS
function drawTile(px,py,conn,alpha){
var S=TS,RW=S*0.4,M=S/2,HR=RW/2,lw=Math.max(1,S/50)
var N=conn[0],E=conn[1],So=conn[2],W=conn[3],sum=N+E+So+W
if(alpha<1)ctx.globalAlpha=alpha
ctx.fillStyle=GREEN;ctx.fillRect(px,py,S,S)
if(sum===1){ctx.fillStyle=ROAD;var st=Math.max(2,S*0.02)
if(N){ctx.fillRect(px+M-HR,py,RW,st);ctx.beginPath();ctx.arc(px+M,py+st,HR,0,Math.PI);ctx.fill()}
if(So){ctx.fillRect(px+M-HR,py+S-st,RW,st);ctx.beginPath();ctx.arc(px+M,py+S-st,HR,Math.PI,0);ctx.fill()}
if(E){ctx.fillRect(px+S-st,py+M-HR,st,RW);ctx.beginPath();ctx.arc(px+S-st,py+M,HR,Math.PI*1.5,Math.PI*0.5);ctx.fill()}
if(W){ctx.fillRect(px,py+M-HR,st,RW);ctx.beginPath();ctx.arc(px+st,py+M,HR,Math.PI*0.5,Math.PI*1.5);ctx.fill()}
ctx.strokeStyle=WHITE;ctx.lineWidth=lw
if(N){ctx.beginPath();ctx.moveTo(px+M-HR,py);ctx.lineTo(px+M-HR,py+st);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M+HR,py);ctx.lineTo(px+M+HR,py+st);ctx.stroke();ctx.beginPath();ctx.arc(px+M,py+st,HR,0,Math.PI);ctx.stroke()}
if(So){ctx.beginPath();ctx.moveTo(px+M-HR,py+S);ctx.lineTo(px+M-HR,py+S-st);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M+HR,py+S);ctx.lineTo(px+M+HR,py+S-st);ctx.stroke();ctx.beginPath();ctx.arc(px+M,py+S-st,HR,Math.PI,0);ctx.stroke()}
if(E){ctx.beginPath();ctx.moveTo(px+S,py+M-HR);ctx.lineTo(px+S-st,py+M-HR);ctx.stroke();ctx.beginPath();ctx.moveTo(px+S,py+M+HR);ctx.lineTo(px+S-st,py+M+HR);ctx.stroke();ctx.beginPath();ctx.arc(px+S-st,py+M,HR,Math.PI*1.5,Math.PI*0.5);ctx.stroke()}
if(W){ctx.beginPath();ctx.moveTo(px,py+M-HR);ctx.lineTo(px+st,py+M-HR);ctx.stroke();ctx.beginPath();ctx.moveTo(px,py+M+HR);ctx.lineTo(px+st,py+M+HR);ctx.stroke();ctx.beginPath();ctx.arc(px+st,py+M,HR,Math.PI*0.5,Math.PI*1.5);ctx.stroke()}
ctx.globalAlpha=1;return}
var isCurve=sum===2&&((N&&E)||(E&&So)||(So&&W)||(W&&N))
if(isCurve){var cx_,cy_,sa,ea
if(N&&E){cx_=px+M+HR;cy_=py+M-HR;sa=Math.PI;ea=Math.PI*0.5}
if(E&&So){cx_=px+M+HR;cy_=py+M+HR;sa=Math.PI*1.5;ea=Math.PI}
if(So&&W){cx_=px+M-HR;cy_=py+M+HR;sa=0;ea=Math.PI*1.5}
if(W&&N){cx_=px+M-HR;cy_=py+M-HR;sa=Math.PI*0.5;ea=0}
ctx.fillStyle=ROAD
if(N)ctx.fillRect(px+M-HR,py,RW,M-HR);if(So)ctx.fillRect(px+M-HR,py+M+HR,RW,M-HR)
if(E)ctx.fillRect(px+M+HR,py+M-HR,M-HR,RW);if(W)ctx.fillRect(px,py+M-HR,M-HR,RW)
ctx.beginPath();ctx.moveTo(cx_,cy_);ctx.arc(cx_,cy_,RW,sa,ea,true);ctx.closePath();ctx.fill()
ctx.strokeStyle=WHITE;ctx.lineWidth=lw;ctx.beginPath();ctx.arc(cx_,cy_,RW,sa,ea,true);ctx.stroke()
if(N){ctx.beginPath();ctx.moveTo(px+M-HR,py);ctx.lineTo(px+M-HR,cy_);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M+HR,py);ctx.lineTo(px+M+HR,cy_);ctx.stroke()}
if(So){ctx.beginPath();ctx.moveTo(px+M-HR,cy_);ctx.lineTo(px+M-HR,py+S);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M+HR,cy_);ctx.lineTo(px+M+HR,py+S);ctx.stroke()}
if(E){ctx.beginPath();ctx.moveTo(cx_,py+M-HR);ctx.lineTo(px+S,py+M-HR);ctx.stroke();ctx.beginPath();ctx.moveTo(cx_,py+M+HR);ctx.lineTo(px+S,py+M+HR);ctx.stroke()}
if(W){ctx.beginPath();ctx.moveTo(px,py+M-HR);ctx.lineTo(cx_,py+M-HR);ctx.stroke();ctx.beginPath();ctx.moveTo(px,py+M+HR);ctx.lineTo(cx_,py+M+HR);ctx.stroke()}
ctx.setLineDash([S*0.07,S*0.05]);ctx.lineDashOffset=-S*0.035;ctx.beginPath()
if(N&&E){ctx.moveTo(px+M,py);ctx.lineTo(px+M,cy_);ctx.arc(cx_,cy_,HR,Math.PI,Math.PI*0.5,true);ctx.lineTo(px+S,py+M)}
if(E&&So){ctx.moveTo(px+S,py+M);ctx.lineTo(cx_,py+M);ctx.arc(cx_,cy_,HR,Math.PI*1.5,Math.PI,true);ctx.lineTo(px+M,py+S)}
if(So&&W){ctx.moveTo(px+M,py+S);ctx.lineTo(px+M,cy_);ctx.arc(cx_,cy_,HR,0,Math.PI*1.5,true);ctx.lineTo(px,py+M)}
if(W&&N){ctx.moveTo(px,py+M);ctx.lineTo(cx_,py+M);ctx.arc(cx_,cy_,HR,Math.PI*0.5,0,true);ctx.lineTo(px+M,py)}
ctx.stroke();ctx.setLineDash([]);ctx.lineDashOffset=0;ctx.globalAlpha=1;return}
ctx.fillStyle=ROAD
if(N)ctx.fillRect(px+M-HR,py,RW,M+HR);if(So)ctx.fillRect(px+M-HR,py+M-HR,RW,M+HR)
if(E)ctx.fillRect(px+M-HR,py+M-HR,M+HR,RW);if(W)ctx.fillRect(px,py+M-HR,M+HR,RW)
ctx.strokeStyle=WHITE;ctx.lineWidth=lw
if(N||So){ctx.beginPath();ctx.moveTo(px+M-HR,N?py:py+M-HR);ctx.lineTo(px+M-HR,So?py+S:py+M+HR);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M+HR,N?py:py+M-HR);ctx.lineTo(px+M+HR,So?py+S:py+M+HR);ctx.stroke()}
if(E||W){ctx.beginPath();ctx.moveTo(W?px:px+M-HR,py+M-HR);ctx.lineTo(E?px+S:px+M+HR,py+M-HR);ctx.stroke();ctx.beginPath();ctx.moveTo(W?px:px+M-HR,py+M+HR);ctx.lineTo(E?px+S:px+M+HR,py+M+HR);ctx.stroke()}
if((N||So)&&(E||W)){ctx.fillStyle=ROAD;ctx.fillRect(px+M-HR+1,py+M-HR-1,RW-2,lw+2);ctx.fillRect(px+M-HR+1,py+M+HR-lw,RW-2,lw+2);ctx.fillRect(px+M-HR-1,py+M-HR+1,lw+2,RW-2);ctx.fillRect(px+M+HR-lw,py+M-HR+1,lw+2,RW-2)}
ctx.strokeStyle=WHITE;ctx.lineWidth=lw;ctx.setLineDash([S*0.07,S*0.05]);ctx.lineDashOffset=-S*0.035
if(sum===2){if(N||So){ctx.beginPath();ctx.moveTo(px+M,py);ctx.lineTo(px+M,py+S);ctx.stroke()};if(E||W){ctx.beginPath();ctx.moveTo(px,py+M);ctx.lineTo(px+S,py+M);ctx.stroke()}}
else if(sum===3){if(!N){ctx.beginPath();ctx.moveTo(px,py+M);ctx.lineTo(px+S,py+M);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M,py+M+HR);ctx.lineTo(px+M,py+S);ctx.stroke();ctx.setLineDash([]);ctx.lineWidth=lw*2;ctx.beginPath();ctx.moveTo(px+M-HR+3,py+M+HR+6);ctx.lineTo(px+M,py+M+HR+6);ctx.stroke();ctx.lineWidth=lw}
if(!So){ctx.beginPath();ctx.moveTo(px,py+M);ctx.lineTo(px+S,py+M);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M,py);ctx.lineTo(px+M,py+M-HR);ctx.stroke();ctx.setLineDash([]);ctx.lineWidth=lw*2;ctx.beginPath();ctx.moveTo(px+M,py+M-HR-6);ctx.lineTo(px+M+HR-3,py+M-HR-6);ctx.stroke();ctx.lineWidth=lw}
if(!W){ctx.beginPath();ctx.moveTo(px+M,py);ctx.lineTo(px+M,py+S);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M+HR,py+M);ctx.lineTo(px+S,py+M);ctx.stroke();ctx.setLineDash([]);ctx.lineWidth=lw*2;ctx.beginPath();ctx.moveTo(px+M+HR+6,py+M);ctx.lineTo(px+M+HR+6,py+M+HR-3);ctx.stroke();ctx.lineWidth=lw}
if(!E){ctx.beginPath();ctx.moveTo(px+M,py);ctx.lineTo(px+M,py+S);ctx.stroke();ctx.beginPath();ctx.moveTo(px,py+M);ctx.lineTo(px+M-HR,py+M);ctx.stroke();ctx.setLineDash([]);ctx.lineWidth=lw*2;ctx.beginPath();ctx.moveTo(px+M-HR-6,py+M-HR+3);ctx.lineTo(px+M-HR-6,py+M);ctx.stroke();ctx.lineWidth=lw}}
else if(sum===4){ctx.beginPath();ctx.moveTo(px+M,py);ctx.lineTo(px+M,py+S);ctx.stroke();ctx.beginPath();ctx.moveTo(px,py+M);ctx.lineTo(px+M-HR,py+M);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M+HR,py+M);ctx.lineTo(px+S,py+M);ctx.stroke();ctx.setLineDash([]);ctx.lineWidth=lw*2;ctx.beginPath();ctx.moveTo(px+M-HR+6,py+M);ctx.lineTo(px+M-HR+6,py+M+HR-3);ctx.stroke();ctx.beginPath();ctx.moveTo(px+M+HR-6,py+M-HR+3);ctx.lineTo(px+M+HR-6,py+M);ctx.stroke();ctx.lineWidth=lw}
ctx.setLineDash([]);ctx.lineDashOffset=0;ctx.globalAlpha=1
}
function drawEmojis(px,py,tile){
if(!tile.emojis)return
ctx.textAlign='center';ctx.textBaseline='middle'
tile.emojis.forEach(function(em){
ctx.font=Math.round(TS*em.s)+'px serif'
ctx.fillText(em.e, px+TS/2+em.x*TS, py+TS/2+em.y*TS)
})
}
// === SIMULATION ===
function recalc(){
var eco=30,sat=35,env=55,traf=10,sup=10,reach=20
for(var r=0;r<ROWS;r++)for(var c=0;c<COLS;c++){
if(!grid[r][c])continue
var tile=TILES[grid[r][c].t],ef=tile.eff||{}
eco+=ef.eco||0;sat+=ef.sat||0;env+=ef.env||0;traf+=ef.traf||0;sup+=ef.sup||0
// Connection check
var conn=rotConn(tile.conn,grid[r][c].r)
var dirs=[[-1,0,0,2],[0,1,1,3],[1,0,2,0],[0,-1,3,1]],any=false
for(var d=0;d<dirs.length;d++){if(!conn[dirs[d][2]])continue;var nr=r+dirs[d][0],nc=c+dirs[d][1]
if(nr>=0&&nr<ROWS&&nc>=0&&nc<COLS&&grid[nr][nc]){var nb=rotConn(TILES[grid[nr][nc].t].conn,grid[nr][nc].r);if(nb[dirs[d][3]])any=true;else traf++}else traf++}
if(tile.cat===1&&!any){reach-=4}else if(tile.cat===1)reach+=3
// Neighbors
if(tile.n==='Wohngebiet'||tile.n==='Hochhäuser'){var nb2=[];if(r>0&&grid[r-1][c])nb2.push(TILES[grid[r-1][c].t]);if(c<COLS-1&&grid[r][c+1])nb2.push(TILES[grid[r][c+1].t]);if(r<ROWS-1&&grid[r+1][c])nb2.push(TILES[grid[r+1][c].t]);if(c>0&&grid[r][c-1])nb2.push(TILES[grid[r][c-1].t])
nb2.forEach(function(n){if(n.n==='Park'||n.n==='Spielplatz'){sat+=2;env+=1};if(n.n==='Fabrik'){sat-=4;env-=3};if(n.n.indexOf('Laden')>=0||n.n.indexOf('Supermarkt')>=0){sup+=2;sat+=1}})}
}
var cl=function(v){return Math.min(100,Math.max(0,Math.round(v)))}
scores={eco:cl(eco),sat:cl(sat),env:cl(env),traf:cl(traf),sup:cl(sup),reach:cl(reach)}
}
function nextRound(){
if(gameOver)return;round++;budget+=income;recalc()
if(round>maxRounds){gameOver=true
var total=Math.round(0.22*scores.eco+0.24*scores.sat+0.18*scores.env+0.16*scores.sup+0.12*scores.reach+0.08*(100-scores.traf))
document.getElementById('end-t').textContent=total>=50?'🎉 Geschafft!':'😔'
document.getElementById('end-p').textContent='Score: '+total
document.getElementById('ov-end').classList.remove('hidden')
return}
renderUI()
}
// === RENDER ===
var hoverR=-1,hoverC=-1
function render(){
ctx.fillStyle='#c8d0b8';ctx.fillRect(0,0,cv.width,cv.height)
for(var r=0;r<ROWS;r++)for(var c=0;c<COLS;c++){
var px=c*TS,py=r*TS,cell=grid[r][c]
if(cell){var conn=rotConn(TILES[cell.t].conn,cell.r);drawTile(px,py,conn,1);drawEmojis(px,py,TILES[cell.t])}
else{ctx.fillStyle=GREEN;ctx.fillRect(px,py,TS,TS)}
ctx.strokeStyle='rgba(0,0,0,0.06)';ctx.lineWidth=0.4;ctx.strokeRect(px,py,TS,TS)
if(r===hoverR&&c===hoverC&&sel>=0&&!cell){drawTile(px,py,TILES[sel].conn,0.3)}
}
requestAnimationFrame(render)
}
function renderUI(){
document.getElementById('h-bud').textContent=budget
document.getElementById('h-rnd').textContent=round+'/'+maxRounds
document.getElementById('h-inc').textContent='+'+income+'/Runde'
if(sel>=0&&budget<TILES[sel].cost)sel=-1
// Params
var ps=[{n:'Wirtschaft',i:'💰',v:scores.eco},{n:'Zufriedenheit',i:'😊',v:scores.sat},{n:'Umwelt',i:'🌿',v:scores.env},{n:'Verkehr',i:'🚗',v:scores.traf,inv:1},{n:'Versorgung',i:'🛒',v:scores.sup},{n:'Erreichbarkeit',i:'🔗',v:scores.reach}]
document.getElementById('params').innerHTML=ps.map(function(p){var g=p.inv?p.v<40:p.v>55,b=p.inv?p.v>65:p.v<30,col=b?'#c07a6b':g?'#5a8a5e':'#c4a35a';return'<div class="param"><div class="param-i">'+p.i+'</div><div class="param-inf"><div class="param-n">'+p.n+'</div><div class="param-bar"><div class="param-bar-f" style="width:'+p.v+'%;background:'+col+'"></div></div></div><div class="param-v" style="color:'+col+'">'+p.v+'</div></div>'}).join('')
document.getElementById('msgs').innerHTML=messages.slice(-5).reverse().map(function(m){return'<div class="msg '+m.type+'">'+m.text+'</div>'}).join('')
// Tools
;[['road-tools',0],['building-tools',1],['nature-tools',2]].forEach(function(pair){
var html='';TILES.forEach(function(t,i){if(t.cat!==pair[1])return;var af=budget>=t.cost
html+='<div class="tb'+(sel===i?' on':'')+(af?'':' off')+'" data-t="'+i+'"><span class="te">'+(t.emoji||'🛣️')+'</span>'+t.n+'<span class="tc">💰'+t.cost+'</span></div>'})
document.getElementById(pair[0]).innerHTML=html})
document.querySelectorAll('.tb').forEach(function(b){b.addEventListener('click',function(){var i=parseInt(this.dataset.t);sel=sel===i?-1:i;renderUI()})})
}
// === INPUT ===
cv.addEventListener('click',function(e){
if(gameOver)return;var rect=cv.getBoundingClientRect(),mx=(e.clientX-rect.left)*(cv.width/rect.width),my=(e.clientY-rect.top)*(cv.height/rect.height)
var gc=Math.floor(mx/TS),gr=Math.floor(my/TS);if(gr<0||gr>=ROWS||gc<0||gc>=COLS)return
var cell=grid[gr][gc]
if(cell){var rx=mx-gc*TS,ry=my-gr*TS;if(ry<TS*0.35){if(rx<TS*0.4){cell.r=(cell.r+3)%4;return};if(rx>TS*0.6){cell.r=(cell.r+1)%4;return}};return}
if(sel>=0&&budget>=TILES[sel].cost){grid[gr][gc]={t:sel,r:0};budget-=TILES[sel].cost;recalc();renderUI()}
})
cv.addEventListener('mousemove',function(e){var rect=cv.getBoundingClientRect();hoverC=Math.floor((e.clientX-rect.left)*(cv.width/rect.width)/TS);hoverR=Math.floor((e.clientY-rect.top)*(cv.height/rect.height)/TS);if(hoverR<0||hoverR>=ROWS||hoverC<0||hoverC>=COLS){hoverR=-1;hoverC=-1}})
cv.addEventListener('mouseleave',function(){hoverR=-1;hoverC=-1})
// Touch support
cv.addEventListener('touchstart',function(e){e.preventDefault();var t=e.touches[0],rect=cv.getBoundingClientRect(),mx=(t.clientX-rect.left)*(cv.width/rect.width),my=(t.clientY-rect.top)*(cv.height/rect.height);var gc=Math.floor(mx/TS),gr=Math.floor(my/TS);if(gr<0||gr>=ROWS||gc<0||gc>=COLS)return;var cell=grid[gr][gc];if(cell){var rx=mx-gc*TS,ry=my-gr*TS;if(ry<TS*0.35){if(rx<TS*0.4){cell.r=(cell.r+3)%4;return};if(rx>TS*0.6){cell.r=(cell.r+1)%4;return}};return};if(sel>=0&&budget>=TILES[sel].cost){grid[gr][gc]={t:sel,r:0};budget-=TILES[sel].cost;recalc();renderUI()}},{passive:false})
cv.addEventListener('touchmove',function(e){e.preventDefault();var t=e.touches[0],rect=cv.getBoundingClientRect();hoverC=Math.floor((t.clientX-rect.left)*(cv.width/rect.width)/TS);hoverR=Math.floor((t.clientY-rect.top)*(cv.height/rect.height)/TS);if(hoverR<0||hoverR>=ROWS||hoverC<0||hoverC>=COLS){hoverR=-1;hoverC=-1}},{passive:false})
document.addEventListener('keydown',function(e){if(e.key==='Escape'){sel=-1;renderUI()}})
document.getElementById('btn-next').addEventListener('click',nextRound)
document.getElementById('btn-go').addEventListener('click',function(){document.getElementById('ov-intro').classList.add('hidden');renderUI()})
document.getElementById('btn-again').addEventListener('click',function(){document.getElementById('ov-end').classList.add('hidden');location.reload()})
recalc();renderUI();render()
</script>
</body>
</html>
@@ -1,126 +0,0 @@
# Kofferdetektiv · Folge-Aufträge für Sim-Entwickler
**Datum:** 2026-06-15
**Kontext:** Nach Vollausbau-Iteration sind drei Punkte aus dem 17-Punkte-Brief offen, weil sie externe Werkzeuge oder größere Sim-Code-Architektur benötigen. Atlas liefert hier Briefing-Material für die nächste Welle.
## Was die Plattform schon liefert
- 46 Glossar-Begriffe (DB), 41 Lehrplan-Anker (AT/CH/DE/LI), Modul-Detailseite mit Bildergalerie
- Sim-Engine: 35 Glossar-Tooltips in Fundsachen, Joystick-Vollanschlag-Sprint (Touch), Audio-Lazy-Load (preload='metadata' statt 'auto'), prominenter Reflexionsfrage-Block mit 40-Zeichen-Minimum
- Datenschutz: `case_country` nur nach Lösung im GGS_LIVE_STATE, vorher nur `case_iso2` für die Lehrer-Sicht
- Reflexionen sichtbar bei Lehrer (Cockpit) + Schüler (Profil)
- 2D-Variante (`/kofferdetektiv-2d`) als WIP-Slot vorbereitet
## Punkt 9 — Englisch-Variante
**Status:** Vorbereitet (alle Texte in `data.js` und UI-Konstanten gebündelt laut INTEGRATION.md).
**Aufgabe:**
- Pro Text-Block zweite Sprach-Variante: `KD_HINTS_EN`, `KD_TUTORIAL_EN`, `KD_FUNDSACHEN_EN`, `KD_GLOSSARY_EN`
- Sprach-Toggle im Header (🌐 DE/EN, persistent in localStorage)
- Plattform-Glossar `glossar.php` müsste eine `?lang=en`-Variante unterstützen — dafür DB-Spalten `short_en`, `text_en` ergänzen
- Lehrplan-Anker bleiben sprachneutral (Quote ist Original-Lehrplan-Text)
**Umfang:**
- ~3.000 Strings zu übersetzen
- DB-Erweiterung + glossar-API-Anpassung
- Sim-Code Sprach-Switch-Logik
- Erweiterung der Plattform: `STUDENT_LANG` parallel zu `STUDENT_EASY`
**Empfehlung:** Erst dann angehen, wenn eine nicht-deutschsprachige Klasse das Modul testet — sonst Investition ohne Validierung.
## Punkt 12 — 3D-Globe-Endscreen
**Status:** Konzept skizziert im 17-Punkte-Brief.
**Aufgabe:** Im Endscreen statt klassischer Score-Liste eine Three.js-Globus-Komponente:
- Erde rotiert (Geschwindigkeit ~10°/s)
- Gelöste Länder leuchten goldgelb (`#e8c547`)
- Ungelöste Länder dunkel
- Klick auf Land → Visitenkarte
- Hover-Hint: „Du hast 4 von 30 Ländern erforscht"
**Technik:**
- Eigene Three.js-Komponente, nicht im Halle-Scene-Graph
- Erd-Modell: Sphere mit Texture (Natural Earth oder NASA Blue Marble, ~2 MB)
- Länder-Polygone: GeoJSON aus Natural Earth 50m (schon in `assets/data/outlines.json` vorhanden)
- Polygon-Extrusion in Three.js für Hover-Effekt
- Performance: Geometrie pre-computed, einmal pro Modul-Start
**Vorbild:** Sonnensystem-Sim hat ähnliche Three.js-Globus-Mechanik.
**Empfehlung:** Größerer Edit, etwa 600-800 LoC. Würde von Sim-Entwickler-Welle (Three.js-erfahren) gut hingebracht werden.
## Punkt 13 — Aussprache-Audio für Wahrzeichen
**Status:** Konzept skizziert.
**Aufgabe:** Schwer auszusprechende Ländernamen und Wahrzeichen bekommen einen 🔊-Knopf in der Visitenkarte, der die Aussprache als kurze MP3 abspielt.
**Liste der Audio-Files (Beispiele):**
- Sigiriya (Sri Lanka)
- Mtatsminda (Georgien)
- Petra tou Romiou (Zypern)
- São Tomé und Príncipe
- Côte d'Ivoire
- Bhutan (Druk Yul)
- ~30 Wahrzeichen + ~30 Hauptstädte = ~60 Audio-Dateien
**Generierung:**
- ElevenLabs (gleicher Workflow wie die 5 PA-Durchsagen im Modul)
- Stimme: ruhig, klar, mit korrekter Phonetik
- Format: MP3, 64 kbps mono, ~3-5 Sek pro Datei, Gesamtgröße ~3 MB
- Pfad: `App/sims/kofferdetektiv/assets/audio/pronounce/<iso2>-<slug>.mp3`
**Sim-Code-Edit:**
- In `fillCountryCard()` einen 🔊-Button neben dem Wahrzeichen-Namen
- Click → neues Audio-Element mit lazy load
- Persistente Audio-Cache wie bei den SFX
**Empfehlung:** Aussprache-Audio ist ein Inklusions-Feature — hilfreich besonders für Lernende mit Lese-Schwierigkeiten oder Easy-Sprache-Flag. Sehr empfehlenswert, mittlerer Aufwand.
## Offene Punkte (kleiner — Atlas oder Sim-Entwickler)
### Punkt 10 — Lehrer-Fall-Verlauf-Tab (Heatmap)
Der View `view=module&student_id=X` liefert schon `runs` mit `results.countries[]`. Atlas könnte im Modul-Detail-Modal (`teacher.html` `openModuleDetail`) für Kofferdetektiv einen Spezialfall einbauen:
- Heatmap-Tabelle: Schüler × Land × Status (gelöst/teilweise/nicht-gelöst)
- Histogramm Hinweis-Effizienz pro Schüler:in
- Trend „Zeit pro Fall" über Durchgänge
**Aufwand:** mittel (200-300 LoC), reines Frontend.
### Punkt 6 — Easy-Sprache durchgängig in Sim-Tutorial
Glossar-Begriffe nutzen schon die Plattform-Mechanik (DB `easy_language`-Auto-Switch). Aber die in-Sim-Texte (Tutorial, Hinweise, Fundsachen-Infos) sind nicht Easy-versioniert. Lösung: pro Text-Block zwei Varianten in `data.js`:
```js
const KD_HINTS_EASY = [
{ key:'population', text: c => `Auf einem Bild steht: In dem Land wohnen etwa ${c.population} Menschen.` },
// …
];
```
Sim zieht Easy-Variante wenn `window.STUDENT_EASY === true`.
**Aufwand:** mittel (~500 Strings zu schreiben).
### Punkt 7 — Bonus-Material Bottom-Sheet
Aktuell zeigt `fillCountryCard()` nach Lösung schon Wahrzeichen-Bild + Trivia + Daten. Ein zusätzlicher Bottom-Sheet wäre Polish, kein Muss. Verschiebbar bis Lehrperson-Feedback.
## Was Atlas selbst noch nachziehen kann
- Punkt 10 Heatmap (mittel, ohne Sim-Entwickler)
- KD_GLOSSARY DB-Spiegelung (erledigt am 2026-06-15)
- Easy-Sprache-Test mit echtem Schüler-Account (STUDENT_EASY=true)
## Briefing-Sicht
Die 3 großen Punkte sind alle „Polish-Plus" — keine blockiert die produktive Nutzung. Empfohlene Reihenfolge:
1. **Punkt 13 Aussprache-Audio** — höchster Inklusions-Wert, mittlerer Aufwand, kann direkt nach Klassen-Test in Auftrag
2. **Punkt 6/10 Easy-Sprache Sim-Tutorial + Lehrer-Heatmap** — Atlas-Inhouse-Arbeit, kann beim nächsten Atlas-Sprint
3. **Punkt 12 3D-Globe-Endscreen** — Sim-Entwickler-Welle, wenn Wal oder andere Three.js-Sim ohnehin in Arbeit
4. **Punkt 9 Englisch** — erst wenn Bedarf konkret vorhanden ist
---
**Kontakt:** Atlas (Plattform-Instanz) — bei Plattform-Fragen direkt fragen, dies hier ist nur ein Auftrags-Briefing.
@@ -1,124 +0,0 @@
# Kofferdetektiv · Integrations-ToDo
**Datum:** 2026-06-14
**Stand:** 3D-Version komplett fertig geliefert (siehe `.humanInput/Kofferdetektiv/app_to_deploy/INTEGRATION.md`). 2D-Version folgt später.
## Was geliefert ist
| Datei | Größe | Inhalt |
|---|---|---|
| `sims/kofferdetektiv/game.html` | 769 LoC | UI, Header, Overlays |
| `sims/kofferdetektiv/engine.js` | 4274 LoC | 3D-Welt + Fall-Logik |
| `sims/kofferdetektiv/data.js` | 1867 LoC | 30 Länder, Glossar, Hinweise |
| `sims/kofferdetektiv/welt.html` | 147 LoC | Welt-Übersicht aller Länder |
| `sims/kofferdetektiv/assets/` | 133 MB | 3D-Modelle, Audio, Bilder, Texturen |
| `pages/kofferdetektiv.php` | Wrapper-Vorschlag |
| `INTEGRATION.md` | Detailbriefing |
## Plattform-Anbindung von der Sim aus
Laut INTEGRATION.md bereits sauber drin:
- Header §4.2 mit `GGS_TUTORIAL.replay()`, 📚, 🔊, 🔄, 🏠
- `GGS_LIVE_STATE()` mit 12 Feldern
- `GGS_TUTORIAL` mit eigenem 5-Schritte-Tutorial
- Submit über `/api/progress.php` mit `__GGS_LIVE__.activeMs`
- localStorage-Autosave `kofferdetektiv.v1`
- Lernarbeit-Sprache
- iPad-tauglich (Touch-Joystick + Blick-Drag, ≥36 px, 16px-Inputs)
- 30 Fall-Länder in Klassen A/B/C, 3 Stufen mit Hinweisverteilung
- 20 Hinweis-Kategorien (Einwohnerzahl, Fläche, BIP, Flagge, Wappen …)
- 12 Flughäfen weltweit als Einsatzort
- 16 MP3 Hintergrundmusik + 8 SFX + 5 PA-Durchsagen
- Länderatlas im Header (gelb/grün-Markierung persistent)
## Atlas-ToDo
### A · Code-Integration (sofort, lokal)
- [x] ToDo-Liste schreiben (diese Datei)
- [ ] Sim-Files nach `App/sims/kofferdetektiv/` kopieren (133 MB)
- [ ] `welt.html` prüfen — was ist das, soll's deployed werden?
- [ ] Wrapper an Plattform-Standard angleichen (mode-locked/teacher_started/free, student_modules-Override, easy_language, locked-Page, WIP-Page wenn game.html fehlt)
- [ ] Sim-File umbenennen auf `game-3d.html` (Vorbereitung 2D-Slot), Wrapper-Pfad anpassen
- [ ] Wrapper `pages/kofferdetektiv-3d.php` aus aktuellem `pages/kofferdetektiv.php` ableiten
- [ ] Platzhalter `pages/kofferdetektiv-2d.php` mit WIP-Page anlegen
- [ ] Platzhalter `sims/kofferdetektiv/game-2d.html` (leer / WIP) anlegen — wartet auf Sim-Lieferung
### B · Datenbank
- [ ] `module_info`-Eintrag (Title „Kofferdetektiv", Icon 🕵️, Status `geplant`, Dauer ~25 min, Alter 11 16)
- SQL: `App/Don_t_Deploy/2026-06-14-kofferdetektiv-module-info.sql`
- [ ] SQL apply auf Prod (WIP-Page wird damit live)
- [ ] Status auf `beta` ziehen, sobald Sim deployed und einmal durchgetestet
- [ ] modul-detail-Partial: Sonderfall für Kofferdetektiv (zwei Buttons: 3D / 2D — analog Klima)
### C · Glossar (Atlas reicht an Glossar-Instanz weiter)
- [ ] 20 Begriffe in `glossar`-Tabelle anlegen mit `module_id='kofferdetektiv'`:
Einwohnerzahl · Fläche · Bevölkerungsdichte · BIP pro Kopf · Lebenserwartung · UN-Mitglied · Staatsform · Zeitzone · Kontinent · Region · Amtssprache · Währung · Nachbarstaat · Klima · Exportprodukt · Hauptstadt · Flagge · Länderumriss · Internet-Domain · Wahrzeichen
- [ ] Easy-Sprache-Variante für jeden Begriff
- [ ] **Kurztexte liegen bereits in `data.js` `KD_GLOSSARY`** — Glossar-Instanz kann sie übernehmen statt neu schreiben
### D · Lehrplan-Anker (Atlas reicht an Lehrplan-Instanz)
- [ ] 8 12 Anker pro Land (AT/CH/DE/LI)
- Mögliche Fachbezüge:
- **AT GW Sek I:** Kompetenz 1.x (Räume und Klimazonen weltweit), 3.x (Vielfalt Länder/Kulturen), 4.x (Migration und Mobilität)
- **CH RZG Sek I:** RZG.4.x (globale Vernetzung), RZG.5.x (Reisen + Verkehr)
- **DE Sek I:** Länder der Welt, globale Mobilität, Kulturkunde
- **Politische Bildung:** Internationale Mobilität, Zoll, Datenschutz im Reisekontext
- [ ] Verknüpfung in DB `module_kompetenz_map` setzen
### E · Lehrer-Backend
- [ ] **admin-modules.html:** Kofferdetektiv als wählbares Modul für Klassen-Freigabe (sollte automatisch funktionieren sobald `module_info` da ist)
- [ ] **Live-Cockpit `live.php`:** `case_country` nur für Lehrpersonen-Sicht durchreichen (im Schüler-Heartbeat NICHT zeigen — Sim trennt das schon, Atlas verifiziert)
- [ ] **LIVE_PRIMARY_FIELDS['kofferdetektiv']** in `teacher.html` einbauen (Vorlage in INTEGRATION.md §Vorschlag)
- [ ] **Ergebnis-Tab `results.php`:** Kofferdetektiv-Submission-Schema (Fall-Liste pro Schüler, Lösungs-Quote pro Land, Hinweis-Effizienz) sichtbar machen
- [ ] **Benchmark::scoreKofferdetektiv()** in `App/php/lib/Benchmark.php` (Formel-Vorlage in INTEGRATION.md §Vorschlag)
- Base 60 % Lösungsquote + 25 % Erstversuch + 15 % Hinweis-Effizienz bis 20 % Fehlversuch-Malus
- [ ] **Reflexionsfrage** automatisch vor Submit zeigen — Sim macht das schon laut INTEGRATION.md, Atlas verifiziert via Playwright
### F · Mode-Steuerung (Plattform-Standard)
- [ ] Wrapper-Hardening: `mode='teacher_started'` mit `forcedLevel` durchreichen (sperrt Stufenwahl in Sim)
- [ ] Wrapper-Hardening: `mode='locked'` mit Locked-Page (Plattform-Standard)
- [ ] Wrapper-Hardening: `student_modules`-Override pro Schüler:in
- [ ] Wrapper-Hardening: `STUDENT_EASY=true` aus `students.easy_language` ableiten
### G · Tests
- [ ] `sims/kofferdetektiv/game.html` `.dontDeploy/playwright/tests/stufe1-smoke/routes-static.spec.js` Slug ergänzen
- [ ] `sim-platform-context.spec.js`: Slug `kofferdetektiv` für `__GGS__ + live-client + GGS_LIVE_STATE`
- [ ] Stufe-2-Flow-Test: Boot → Onboarding → Erster Fall starten → GGS_LIVE_STATE liefert `case_index/cases_total`
- [ ] Performance-Check: Boot-Zeit auf iPad-equivalentem Viewport unter ~5s (3D-Modelle sind 1,8 MB + 0,3 MB)
### H · Card-Image + Modul-Detailseite
- [ ] `App/assets/img/card-kofferdetektiv.png` generieren (Flat Scandinavian, Atlas)
- [ ] Modul-Detailseite `modul-kofferdetektiv` (Plattform-Standard, kommt automatisch durch `modul-<id>.php`-Partial wenn `module_info` da ist)
- [ ] DALL-E-Prompt: „Flat scandinavian illustration, airport luggage counter at night, detective with magnifying glass over open suitcase, soft warm palette …"
### I · Deploy-Sequenz
- [ ] **Schritt 1 jetzt:** module_info-SQL apply → WIP-Page live unter `geograsim.at/kofferdetektiv-3d`
- [ ] **Schritt 2:** Wrapper + Sim-Files lokal vorbereiten + integrieren (Atlas heute)
- [ ] **Schritt 3:** Thomas-Test lokal → Feedback
- [ ] **Schritt 4:** Deploy Sim-Files + Wrapper auf Prod
- [ ] **Schritt 5:** Status `geplant``beta`
- [ ] **Schritt 6:** Playwright-Suite ergänzen + grün ziehen
- [ ] **Schritt 7:** Glossar + Lehrplan-Anker an Schwester-Instanzen
### J · 2D-Version (offen, später)
- [ ] Konzept für 2D-Variante mit Thomas klären
- Gleiche Mechanik als 2D-Top-Down-Variante?
- Vereinfachte iPad-First-Variante ohne 3D-Performance-Anforderungen?
- Mini-Spiel-Variante (z. B. einzelner Koffer als Drag-Drop)?
- [ ] Sim-Lieferung abwarten
- [ ] `sims/kofferdetektiv/game-2d.html` einsetzen
- [ ] Wrapper `pages/kofferdetektiv-2d.php` aktivieren
- [ ] modul-detail: zweiten Button freischalten
### K · Optional / Folgearbeit
- [ ] Glossar-Tooltip-Plattform-Lib mit `KD_GLOSSARY` aus data.js synchronisieren (DB-Single-Source-of-Truth)
- [ ] Reise-Plakate in der 3D-Halle: Lehrplan-Verweis pro Land
- [ ] Welt-Übersicht (`welt.html`) — eigene Sub-Route oder per Atlas-Header zugänglich machen?
- [ ] Audio-Lizenz-Doku: ElevenLabs-Sprachausgaben + Sketchfab-Lizenzen abklären
---
**Sofort-Plan:** A (Code), B (DB+SQL+WIP-Deploy) — beides geht heute.
**Mittelfrist:** C, D, E, F (Glossar, Lehrplan, Lehrer-Backend, Mode-Hardening) — über die nächsten Sessions.
**Nach Thomas-Test:** G (Tests), H (Card-Image), I (Deploy-Sequenz Sim-Files).
**Wartend:** J (2D-Version).
@@ -1,161 +0,0 @@
# Kofferdetektiv · Verbesserungsvorschläge
**Datum:** 2026-06-15
**Sicht:** Atlas (Plattform-Instanz), nach Vollausbau Glossar + Lehrplan
**Vorgehen:** sortiert nach Effekt vs. Aufwand
---
## Sicht von außen — die Sim ist didaktisch eine Schatzkiste
30 Fall-Länder, 20 Hinweis-Kategorien, 30 Fundsachen mit didaktisch starken Info-Texten, 12 Flughäfen weltweit, 16 Hintergrund-Musikstücke, ~190 Länder zum Auswählen. Das macht den Kofferdetektiv zum **inhaltsstärksten** Modul der Plattform. Die meisten Verbesserungen sind keine Lücken-Schließer, sondern Hebel um das Material noch besser sichtbar zu machen.
---
## Hoher Effekt, kleiner Aufwand
### 1. Glossar-Tooltips IN den Fundsachen-Texten verlinken
Die Fundsachen-Toasts erklären jetzt großartige Dinge („100-ml-Regel", „Roaming", „Powerbank-Sicherheit"). Die 26 neuen Glossar-Begriffe sind alle in der DB — aber die Sim-Toasts verlinken sie noch nicht.
**Aufwand:** Sim-Engine markiert in den Texten Schlagwörter mit `<span class="ggs-g" data-glossar="…">…</span>` (Plattform-Standard, glossar-tooltip.js ist schon eingebunden). Vorlage:
```
"Powerbanks müssen ins <span class='ggs-g' data-glossar='akku-handgepaeck'>Handgepäck</span>,
nie in den aufgegebenen Koffer..."
```
**Effekt:** Lernende klicken den Begriff → sehen Easy-Sprache-Variante. Lehrperson kann darauf bauen, dass das Vokabular klickbar ist.
### 2. Reflexionsfrage prominenter
INTEGRATION.md sagt: Reflexionsfrage „Welcher Hinweis hat dir am meisten geholfen — und welcher Fall war am schwierigsten? Begründe kurz" vor dem Submit. Falls die nur als kleines Textfeld kommt: stärker akzentuieren. Vorschlag: Vollbild-Modal mit dem Bild aus `intro/fall-abgeben.webp`, klares Layout, Submit-Button erst nach Mindest-Text-Länge aktiv (40+ Zeichen).
**Effekt:** echte didaktische Reflexion statt Klick-durch.
### 3. Lehrer-Sicht: case_country prüfen auf Datenschutz
Im Cockpit zeigt `LIVE_PRIMARY_FIELDS['kofferdetektiv']` das Zielland mit Kommentar „nur Lehrpersonen-Sicht". Aber: wenn der Sim den `case_country` in `GGS_LIVE_STATE` einbettet, ist er für Schüler:innen über DevTools im JavaScript sichtbar — der „Lehrer-only" Hinweis ist nur in der teacher.html-Render-Logik. Empfehlung:
- **Variante A:** Sim soll `case_country` **nicht** in GGS_LIVE_STATE liefern. Atlas liest in `/api/live.php` aus der Sim-internen DB (z. B. aus `kofferdetektiv_cases`-Log oder aus dem letzten `assessments.results.countries[]`-Eintrag), nur an Lehrpersonen-Endpoint.
- **Variante B:** Sim verschlüsselt `case_country` mit einem pro-Klasse-Schlüssel, den nur der Lehrer-Cockpit-Backend hat.
Für Pilot-Phase reicht Variante A; das Schüler:innen-Frontend bekommt keinen Anlass, in DevTools zu schauen.
### 4. Welt-Übersicht `welt.html` aus dem Header zugänglich machen
Die existierende `welt.html` (147 LoC, Welt-Atlas-Übersicht aller Länder) ist live unter `/sims/kofferdetektiv/welt.html`, aber nicht verlinkt. Vorschlag: kleiner Header-Button 🌍 im Sim-Header, der die welt.html im neuen Tab öffnet — als Begleit-Referenz „Welt-Übersicht aller 190 Länder".
**Effekt:** Lernende haben ein „großes Bild" zur Hand, didaktisch parallel zur Detektivarbeit.
### 5. Card-Image-Variation für die anderen Cockpit-Stellen
Aktuell: `card-kofferdetektiv.webp` ist die Standard-Karte. Für die Modul-Detailseite + Hero könnte ein zweites Bild („Detektiv mit Lupe über Koffer-Inhalt", aus `assets/img/intro/intro-koffer.webp` oder `intro-terminal.webp`) als Hero-Banner dienen.
---
## Mittlerer Effekt, mittlerer Aufwand
### 6. Easy-Sprache-Modus durch die ganze Sim
Wenn `window.STUDENT_EASY === true`, sollte die Sim:
- statt `KD_GLOSSARY` die Easy-Variante aus DB ziehen (oder lokal eigene Easy-Variante im data.js)
- Hinweis-Texte vereinfachen („Eine Infografik nennt etwa 110 Menschen pro km²" → „Auf einem Bild steht: ungefähr 110 Menschen leben auf 1 Quadrat-Kilometer")
- Wahrzeichen-Bilder ggf. mit Bild-Beschreibung als Alt-Text
- Fundsachen-Infos auf Easy-Sprache-Version umstellen
**Aufwand:** mittel; pro Sektion ein Easy-Pendant. Plattform liefert STUDENT_EASY schon, Sim muss es nur auswerten.
### 7. „Bonus-Material" als Bottom-Sheet zu jedem gelösten Land
Nach Lösung eines Falls könnte ein Bottom-Sheet zusätzliche Info zeigen:
- 1 Wahrzeichen-Foto (gibt's schon in `assets/img/landmarks/`)
- 1 Faktbox aus dem Sim-internen Wissen
- Link zum vollen Glossar-Eintrag der nationalen Symbole (Flagge / Wappen / Staatsform)
**Aufwand:** mittel; UI-Komponente + 30 kurze Texte.
**Effekt:** vertieft das Lernen statt Klick-Bestätigung.
### 8. Performance-Profil dokumentieren
133 MB Sim-Assets, davon 1,8 MB Three.js-Modell (Airport-Diorama) + ~80 MB Hintergrundmusik (16 MP3). Auf Prod ist das fein, weil HTTP/2 und Cache, aber:
- iPad-Erstaufruf könnte langsam wirken
- Schul-Internet mit niedriger Bandbreite testen
- Audio kann später nachgeladen werden (lazy-load nach Boot)
**Empfehlung:** Audio-Verzeichnis `assets/audio/music/` mit `<audio preload="none">` Pattern, lädt erst beim Play.
### 9. Mehrsprachigkeit vorbereitet → tatsächlich Englisch ergänzen
INTEGRATION.md sagt: „Mehrsprachigkeit vorbereitet, alle Texte in data.js/UI-Konstanten gebündelt". Für DACH-Klassen mit nicht-deutschsprachigen Lernenden wäre Englisch-Variante nützlich. Vorschlag: `KD_TEXTS_DE`/`KD_TEXTS_EN`, Schalter im Header.
**Aufwand:** groß (alle Texte übersetzen). **Effekt:** Klassen-Inklusion.
---
## Hoher Effekt, größerer Aufwand
### 10. Lehrer-Auswertung „Fall-Verlauf pro Schüler:in"
Im Lehrer-Cockpit (`results.php`) könnte für Kofferdetektiv ein eigener Tab kommen:
- **Welche Länder** hat Schüler:in X gelöst (Heatmap)
- **Welche Hinweise** wurden am häufigsten gebraucht (Histogramm)
- **Zeit pro Fall** als Trend
- **Reflexionsantworten** als Text-Liste
Schema `assessments.results.countries[]` aus INTEGRATION.md liefert das Material schon. Atlas baut die Auswertung in results.php (ähnlich Heli oder Klima).
### 11. Klassen-Vergleichsmodus
Lehrperson startet `mode='teacher_started'` mit `forcedLevel=2` für die ganze Klasse. Cockpit zeigt: alle Schüler:innen → selbe Stufe → wer hat welches Land schon? Echtzeit-Wettbewerb (ohne Punkte-Druck).
### 12. Globe-Visualisierung im Endscreen
Statt klassischer Score-Liste am Ende: 3D-Globus rotiert, gelöste Länder leuchten goldgelb, ungelöste sind dunkel. „Du hast 4 von 30 Ländern erforscht." Klick auf Land → öffnet noch mal die Visitenkarte.
**Aufwand:** groß (Three.js-Globus + Daten-Binding). **Effekt:** emotionaler Abschluss, klares „mehr ist möglich" Signal.
### 13. Aussprache-Audio für nicht-deutsche Wahrzeichen
30 Wahrzeichen — manche schwer zu lesen (Sigiriya, Mtatsminda, Kotor). Ein 🔊-Knopf in der Visitenkarte spielt die Aussprache (ElevenLabs könnte das vorgenerieren). 30 × ~5 Sekunden = 30 kleine MP3.
**Effekt:** Inklusion für Lernende mit Lese-Schwierigkeiten + Sprach-Vorbild.
---
## Polish und Konsistenz
### 14. Texte-Audit gegen Sprachkonvention
INTEGRATION.md sagt „Lernarbeit-Sprache". Stichprobenartig prüfen:
- Kein „Spiel", „Spielen", „Spieler"
- „Durchgang" statt „Runde"
- „Lehrperson" statt „Lehrkraft"
### 15. Glossar-Begriffe in DB → in `data.js` `KD_GLOSSARY` spiegeln
Die 26 neuen Begriffe sind in der DB, aber `data.js` `KD_GLOSSARY` enthält nur die 20 Hinweis-Kategorien. Für den Fall, dass die Sim offline läuft (Standalone-Test), wäre Konsistenz schön — Atlas könnte ein Python/Node-Script anbieten, das beide Quellen abgleicht.
### 16. Image-Sitemap für Modul-Detailseite
Auf der Modul-Detailseite (`modul-kofferdetektiv`) könnte ein kleiner Bildergalerie-Streifen zeigen: 4-5 In-Sim-Screenshots (Flughafen 3D, Analyse-Ansicht, Visitenkarte, Endscreen, Atlas-Übersicht). Aktuell nur eine Hero-Card.
### 17. Lehrplan-Anker erweitern
Aktuell 8 AT-Anker + 6 CH + 4 DE + 2 LI. Für die volle Tiefe könnten 12 pro Land kommen — z. B. fächerübergreifend in DE die Verbindung zu Wirtschaft/Recht (Verbraucherbildung) und Politik (Internationale Beziehungen).
---
## Was Atlas direkt nachziehen kann (heute oder morgen)
- ✓ Glossar +26 Begriffe (erledigt)
- ✓ Lehrplan-Kompetenzen + 20 Anker (erledigt)
- ✓ Modul-Detail-Seite mit Dual-Button (erledigt)
- ✓ Card-Image (erledigt)
- ⏳ Punkt 4 — Welt-Header-Link auf welt.html
- ⏳ Punkt 5 — Hero-Banner zweites Bild für Modul-Detail
- ⏳ Punkt 16 — Bildergalerie auf Modul-Detail
## Was Sim-Entwickler-Eingriff braucht
- Punkt 1 — Glossar-Tooltips in Fundsachen-Texten
- Punkt 2 — Reflexion-Modal prominenter
- Punkt 3 — case_country aus GGS_LIVE_STATE entfernen
- Punkt 6 — Easy-Sprache durchgängig
- Punkt 7 — Bonus-Material-Bottom-Sheet
- Punkt 9 — Englisch-Variante
- Punkt 12 — Globe-Endscreen
- Punkt 13 — Aussprache-Audio
- Punkt 15 — KD_GLOSSARY mit DB abgleichen
## Was im Plattform-Backend kommt
- Punkt 10 — Lehrer-Cockpit Fall-Verlauf-Tab
- Punkt 11 — Klassen-Vergleichsmodus
---
**Empfehlung Reihenfolge:** Punkt 4 + 5 + 16 sind heute machbar (UI-Polish auf Plattform-Seite). Punkt 1 + 6 sind die größten Hebel für didaktische Tiefe und sollten als nächstes mit dem Sim-Entwickler abgestimmt werden.
@@ -1,86 +0,0 @@
# Deployment-Pending · Stand 2026-06-11
Atlas hat seit 2026-06-10 keinen automatischen Deploy mehr gemacht (Thomas-Regel).
Folgende Fixes liegen **lokal** und sind **noch nicht auf Prod**:
## Kritisch — User-sichtbarer Bug auf Prod
### 1. Klima 2D + 3D · Glossar-Tooltip-Link
**Auf Prod aktuell defekt** — vom Playwright-Run 2026-06-11 02:53 nachgewiesen.
- **Symptom**: in Klima-Sim auf einen Fachbegriff klicken → Popup zeigt
„Voller Glossar-Eintrag →" → Klick öffnet `https://geograsim.at/klima-2d/glossar?term=budget`
(relativer Pfad) → **404**.
- **Root Cause**: `__GGS__.basePath` ist auf Prod ein leerer String `""`.
Truthy-Check in `App/sims/klima/game-2d.html:4193` und `game-3d.html:5699`
fiel deshalb fälschlich auf den Fallback `/geograsim/App` zurück.
- **Fix lokal seit 2026-06-10**: `typeof basePath === 'string'` statt
Truthy-Check. Greift sofort, wenn deployt.
- **Test-Skript**: `.dontDeploy/playwright/tests/stufe1-smoke/glossar-tooltip-regression.spec.js`
## Mittelschwer — Polish/Konsistenz
### 2. Lehrer-Cockpit (neu)
`App/teacher.html` + `App/php/api/live.php` haben einen komplett neuen
„🎯 Cockpit"-Modus (Status-Tiles, Top 3/Bottom 3, Klassen-Säulen,
Schülerliste). Plus `App/php/lib/Benchmark.php` als neue Lib.
Live nur lokal, Prod hat noch den alten Live-Tab.
### 3. Farmer-Sim · GGS_LIVE_STATE erweitert
`App/sims/farmer/game.html` liefert jetzt `simId`, `phase`, `progressPct`
auf Prod fehlt das. Folge: im Lehrer-Cockpit (sobald deployt) zeigt
Farmer keine Phase-Beschriftung.
### 4. Weltküche · Moussaka-Lamm-Datenmodell
`App/sims/weltkueche/assets/data/production-matrix.json` + `dishes.json`
haben neue Zutat `lamm` und Moussaka nutzt sie. Plus
`App/pages/weltkueche-uebersicht.html` neu generiert.
### 5. Weltküche · 6 SFX-Files
`App/sims/weltkueche/sounds/*.mp3` (6 Files, je 941 KB) sind lokal,
nicht auf Prod. Spiel funktioniert auch ohne, aber Audio-Feedback fehlt.
### 6. Modul-Info-Seiten Weltküche + Fluggesellschaft
`App/pages/modul-weltkueche.php` und `modul-fluggesellschaft.php` — auf
Prod 404, lokal 200.
### 7. Heli M6 Mellau-Bug
DB-Update auf Prod schon gemacht (Mellau-Lat/Lon korrigiert), aber
`App/sims/heli/game.html` mit Startfreigabe-Validierung NICHT deployed.
## Klein — Sprache/Mapping
### 8. Weltküche Sprach-Fix
„aus dort kaufen" → „von dort bekommen" — lokal gefixt, Prod hat noch
den alten Text.
### 9. Glossar-Tooltip-Lib
`App/assets/js/glossar-tooltip.js` Regex erweitert für `/php/api`
gilt für die Weltküche-Tooltips. Lokal gefixt, Prod hat noch die
alte Regex.
---
## Empfehlung an Thomas
Wenn der Deployment-Stopp eine Pause auf bestimmte Risiken war:
- **Mindestens den Klima-Glossar-Bug** sollten wir deployen — der ist
jetzt sichtbar in jeder Klima-Sim-Sitzung, jeder Klick auf einen
Fachbegriff landet im 404.
- Idealerweise alles oben Listed in einem **gebündelten Deploy**.
Wenn der Stopp aber etwas mit dem Live-Cockpit zu tun hat (Backend-Erweiterung):
- Den Cockpit-Stuff abtrennen und schrittweise rollen.
Atlas wartet auf grünes Licht, bevor irgendetwas hochgeht.
— Atlas · 2026-06-11
@@ -1,69 +0,0 @@
# Brief an Meister · `www.geograsim.at` lädt nicht im Browser
**Stand 2026-06-11** · Beobachtung von Thomas, Diagnose von Atlas.
## Symptom
- `https://geograsim.at/glossar` → funktioniert
- `https://www.geograsim.at/glossar` → lädt im Browser nicht
## Was schon geprüft ist (Diagnose von Atlas, read-only auf Prod)
| Aspekt | Status |
|---|---|
| DNS-Auflösung beider Subdomains | ✓ beide → 85.215.155.82 (geprüft via `1.1.1.1`) |
| Apache-VirtualHost `002-geograsim.conf` | ✓ enthält `ServerAlias www.geograsim.at` |
| HTTP vom Server lokal (curl mit `--resolve`) | ✓ beide URLs liefern HTTP/2 200 |
| SSL-Zertifikate | ⚠️ **zwei separate Let's-Encrypt-Certs** |
## Cert-Detail
```
geograsim.at:
CN = geograsim.at
Issuer: Let's Encrypt E7
SAN: DNS:geograsim.at ← nur eine Domain im Cert!
notAfter: 12.07.2026
www.geograsim.at:
CN = www.geograsim.at
Issuer: Let's Encrypt E8
SAN: vermutlich nur www.geograsim.at
notAfter: 12.07.2026
```
→ Vermutung: Apache lädt nur eines der beiden Certs in den 443-VirtualHost, und SNI-Fallback funktioniert für den jeweils anderen Host nicht. Browser zeigt dann SSL-Fehler statt 200.
## Was zu tun ist (Vorschlag, du kennst das besser)
### Option A — empfohlen: Multi-SAN-Cert aus beiden machen
```bash
certbot --apache --cert-name geograsim.at \
-d geograsim.at -d www.geograsim.at
```
Das erzeugt **ein einzelnes Cert** mit beiden Hostnames in SAN. Sauberer als zwei separate Certs. Apache-Auto-Renew funktioniert automatisch weiter.
### Option B — zusätzlich: 301-Redirect `www → apex`
In `002-geograsim.conf` ergänzen (oder als eigene `.htaccess`-Regel):
```apache
<VirtualHost *:443>
ServerName www.geograsim.at
RewriteEngine On
RewriteRule ^(.*)$ https://geograsim.at$1 [R=301,L]
</VirtualHost>
```
Vorteil: eine kanonische Domain (besser für SEO + Tracking-Konsistenz). Schüler:innen + Lehrpersonen sehen immer `geograsim.at` ohne `www`.
## Was Atlas weiter braucht von Thomas
Falls die Lösung nicht greift: Screenshot aus den Browser-Devtools beim Aufruf von `https://www.geograsim.at/glossar` mit der konkreten Fehler-Meldung (z.B. `NET::ERR_CERT_COMMON_NAME_INVALID` oder `ERR_SSL_PROTOCOL_ERROR`) — daraus lässt sich genauer sehen, ob es ein Cert- oder Routing-Problem ist.
---
*Atlas-Memory:* die Datei liegt unter `.dontDeploy/notes/2026-06-11-domain-www-an-meister.md`,
nicht im Git getrackt (eigentlich schon gitignored, weil unter `.dontDeploy/`).
@@ -1,42 +0,0 @@
# Relevante Infos für Lehrpersonen — Zusammenfassung
Stand 2026-08-19. Konsolidiert, was wir zum Lehrer-Cockpit festgehalten und gebaut haben.
## Die Kernfrage der Lehrperson
> „Wer ist gerade **engagiert und macht es gut** — und wer **blödelt herum oder hängt fest**?"
Alles im Cockpit dient dieser Frage. Kein Zahlen-Dump, sondern wenige aussagekräftige Signale.
## Die 6 relevanten Signale
| Signal | Was es beantwortet | Woher |
|---|---|---|
| **Fortschritt** | Wie weit durch die Sim? (%) | `progressPct` / abgeleitet je Sim |
| **Qualität** | Blödeln vs. gut — Verhältnis **richtige ↔ falsche** Klicks (grafischer Balken) | `correctClicks`/`wrongClicks` (bisher Weltküche; andere ziehen nach) |
| **Fleiß** | Wie viel im **gewählten Zeitraum** geschafft? (z. B. Gerichte, gelieferte Aufträge) | assessments im Intervall |
| **Lage** | Klartext: **Stark / Solide / Viele Fehler** (kein „Kritisch"-Jargon) | `_liveMood` je Sim |
| **Aktivität** | aktiv / idle / **pausiert** — war das Kind die ganze Stunde dabei? | Heartbeat `__activeMs`/`__idleMs`/`__paused` |
| **Hilfe-Bedarf** | „🆘 braucht evtl. Hilfe" | `_liveNeedsHelp` je Sim (z. B. Budget < 0, viele Fehlversuche) |
## Die Ansichten (Menü „Ergebnisse")
- **📅 Tag** — Zeitstrahl aller Sessions des Tages je Kind, eingefärbt nach Erfolg. Balken tragen **Sim-Kürzel/Wort** (LOG, Logistik …), Klick öffnet Detail.
- **🔴 Aktuell** — Live-Tabelle je Sim mit **kuratierten** Spalten (LIVE_PRIMARY_FIELDS), Qualitäts-Balken, Fortschritt, Lage. Aktualisiert alle 4 s.
- **📊 Vergleich** — aktive Kinder EINER Sim nebeneinander (Fortschritt + Qualität) → direkter „wer gut / wer nicht".
- **📚 Gesamt** — Aggregat (Fleiß-Zeit, Modul-Karten, Matrix) über den gewählten Zeitraum.
## Design-Prinzipien (verbindlich)
1. **Kuratierte Spalten je Sim** — nie Roh-State dumpen, nie interne `__`-Heartbeat-Keys zeigen. Fehlt ein Schema → gefilterter Fallback (ohne Rausch-Felder).
2. **Klartext statt Jargon** — „Stark/Solide/Viele Fehler" statt „Kritisch/OK"; „Gerade dabei" statt „Phase".
3. **Ehrliche Zeit** — Aktivzeit zählt **nicht** bei Spiel-Pause und **nicht** bei Tab-weg/idle (>5 min). Sonst wirkt ein pausiertes Kind fälschlich „fleißig".
4. **Ein Wort + 3-Buchstaben-Kürzel je Sim** (SIM_LABELS) — enge Balken nutzen das Kürzel, breite das Wort.
5. **Datenschutz** — nur was die Lehrperson pädagogisch braucht; verdeckte Antworten (z. B. Kofferdetektiv-Ziel) bleiben verdeckt, solange das Kind sucht.
## Was jede Sim liefern sollte (GGS_LIVE_STATE)
- `progressPct` (0100), ein Fortschritts-Zähler (z. B. `completed`/`total`),
- **`correctClicks`/`wrongClicks`** (für die Qualitäts-Kennzahl — Ziel: alle Sims),
- optional `health` (good/ok/struggling) für die Lage,
- Heartbeat-Felder (`__activeMs` etc.) kommen automatisch aus live-client.js; bei Pause `window.__GGS_LIVE__.setPaused(true)` rufen.
## Offen (siehe project_backlog_2026-08-18 / project_lehrer_observability_overhaul)
- **Aktivitäts-/Qualitätsstreifen** pro Kind über die Stunde (grün→rot, aktiv→inaktiv & bullshit→ernsthaft) — braucht Zeitreihen-Aktivitätsdaten.
- Weltküche-**Gesamt-Kachel** (Gerichte · Ø Punkte · Fehlquote).
- **Andere Sims** mit `correctClicks`/`wrongClicks` nachrüsten (bisher nur Weltküche).
-6
View File
@@ -1,6 +0,0 @@
node_modules/
reports/
test-results/
playwright-report/
.playwright/
*.log
-145
View File
@@ -1,145 +0,0 @@
# GeoGraSim · Playwright-Test-Suite
**Zweck**: automatisierte Browser-Tests, die das halbe Hundertfach manuelles Durchklicken
ersetzen. Sucht tote Links, geänderte UI-Verhalten, Glossar-Tooltip-Bugs etc.
**Wichtig — Plattformregel**: dies ist eine **Lokal-Test-Suite**. Sie läuft gegen
`http://localhost/geograsim/App/...` (XAMPP). Sie deployt nichts und modifiziert keine
Prod-Daten. Falls jemals Prod-Tests gebraucht werden, muss das explizit konfiguriert sein.
---
## Drei Test-Stufen
| Stufe | Was wird getestet | Tool | Wer macht's | Wann läuft's |
|---|---|---|---|---|
| **1** | Statische Link-Checks · Glossar-Slugs · Sim-Wrapper · Nav-Routes | Playwright headless (Chromium) | Atlas baut + lässt laufen | täglich oder vor jedem Commit |
| **2** | End-to-End-Flows: Login · Sim durchspielen · Submit · Lehrer-Cockpit | Playwright headless + headed bei Debug | Atlas baut + lässt laufen | vor jedem geplanten Deploy |
| **3** | Semantische Review: passt didaktisch · UX · Sinnhaftigkeit | Codex (OpenAI) liest Stufe-1-/2-Reports | Atlas baut Briefing-Bundle · Codex schreibt Review · Thomas moderiert | nach größeren Änderungen oder ad hoc |
---
## Verzeichnisstruktur
```
.dontDeploy/playwright/
├── README.md ← dieses File
├── package.json ← npm-Dependencies
├── playwright.config.js ← globale Konfig (baseURL, retries, reporter)
├── .gitignore ← node_modules + Reports werden ignoriert
├── tests/
│ ├── stufe1-smoke/
│ │ ├── links-static.spec.js ← Nav-Links, Top-Menü, Footer
│ │ ├── glossar-all.spec.js ← jeder Glossar-Slug ist erreichbar
│ │ ├── sim-wrappers.spec.js ← jeder Sim-Wrapper antwortet 200 + rendert
│ │ └── api-routes.spec.js ← /api/*-Endpunkte antworten (auth-aware)
│ │
│ └── stufe2-flows/
│ ├── login-klassen-code.spec.js
│ ├── sim-klima-start-bis-submit.spec.js
│ ├── teacher-cockpit-tabs.spec.js
│ └── glossar-tooltip-popup.spec.js
├── fixtures/
│ ├── known-glossar-slugs.json ← aktuelle Liste aller Glossar-Slugs
│ ├── known-paths.json ← alle erwarteten Top-Level-Routes
│ └── test-accounts.json ← Lokal-Test-Schüler:innen + Lehrer
├── reports/ ← gitignored: HTML-Reports + Screenshots
│ └── (autogeneriert)
└── briefing/
├── CODEX-BRIEF.md ← Liebe-Kollege-Brief an Codex
├── codex-stufe-3-auftraege.md ← konkrete Review-Aufträge
└── _context-bundle/ ← Anlagen für Codex
├── geograsim-readme.md ← Auszug aus CLAUDE.md
├── projektkonventionen.md ← Sprach-Regeln, Bildstil, Lehrplan
├── glossar-pattern.md ← Tooltip-Pattern, Bug-Historie
└── sim-architektur.md ← Wrapper, GGS_LIVE_STATE, Live-Cockpit
```
---
## Einrichtung lokal
```bash
cd .dontDeploy/playwright
npm install
npx playwright install chromium # nur Chromium reicht für die meisten Tests
```
Hinweis: `npm install` zieht `node_modules/` ins Verzeichnis (~250 MB). Das ist
via `.gitignore` ausgeschlossen.
---
## Tests laufen lassen
```bash
# Stufe 1 (Smoke): ~30 Sekunden, headless
npm run test:smoke
# Stufe 2 (Flows): ~3 Minuten, headless
npm run test:flows
# Beides hintereinander
npm test
# Mit UI-Debugger (headed, langsam, sehr nützlich beim Debuggen)
npm run test:debug
# Nur ein Test-File
npx playwright test glossar-all.spec.js
# HTML-Report öffnen
npm run report
```
---
## Was Stufe 1 macht (Smoke)
- **Alle Glossar-Slugs anfahren** (aus DB-Dump in `fixtures/known-glossar-slugs.json`):
jeden `/glossar?term=<slug>` aufrufen, prüfen ob 200 + Begriff-Titel im DOM
- **Alle Top-Level-Routes** (`fixtures/known-paths.json`):
`/teacher`, `/schueler`, `/lehrplan`, `/glossar`, `/heli-game`, `/klima-2d`, ...
- **Alle Sim-Wrapper** öffnen, prüfen ob `window.__GGS__` gesetzt ist + game-DOM rendert
- **Glossar-Tooltip-Links auf zentralen Seiten** (Klima-Onboarding, Weltküche): clicken,
prüfen ob Popup öffnet + Link zum vollen Eintrag funktioniert (Regression für den
Bug vom 2026-06-10!)
## Was Stufe 2 macht (Flows)
- **Schüler-Login** mit Klassen-Code + Pseudonym + Passwort
- **Klima starten · 10 Klicks machen · submit**: prüft assessment-Submit + Heartbeat
- **Heli M1 · alle Wegpunkte klicken · Startfreigabe**: prüft die Startfreigabe-Logik
vom 2026-06-10 (Audio-Ende alleine reicht NICHT)
- **Weltküche Pizza · zwei richtige Länder · solved**: prüft Round-End-Anzeige
- **Lehrer-Cockpit · alle 5 Tabs durchklicken**: prüft alle Render-Funktionen
- **Glossar-Tooltip in Weltküche**: Begriff klicken → Popup → „Voller Eintrag" → 200
## Was Stufe 3 macht (Codex-Review)
Codex bekommt:
- HTML-Reports aus Stufe 1 + 2
- Screenshots der wichtigsten Stellen
- Briefing aus `briefing/CODEX-BRIEF.md`
- Kontext-Bundle aus `briefing/_context-bundle/`
Codex schreibt zurück:
- Markdown-Review mit Fundstellen, Schweregrad, Empfehlungen
- KEINE Code-Änderungen — nur Bewertung
---
## Wartung
- **Bei jedem Glossar-Update**: `fixtures/known-glossar-slugs.json` neu dumpen
(siehe `scripts/dump-glossar-slugs.sql`)
- **Bei jeder neuen Sim**: `fixtures/known-paths.json` ergänzen + neuen Flow-Test bauen
- **Bei jedem Bug-Fix**: ein Regressionstest dazu, damit der Bug nicht wiederkommt
---
Stand: 2026-06-11 · gepflegt von Atlas (Claude Opus 4.7) · Reviews durch Codex (GPT-5/4o)
-34
View File
@@ -1,34 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const b = await chromium.launch(); const p = await b.newPage();
const errs=[]; p.on('pageerror',e=>errs.push(e.message)); p.on('console',m=>{if(m.type()==='error')errs.push(m.text());});
await p.route('**/api/admin', r => r.fulfill({ contentType:'application/json', body: JSON.stringify({authenticated:true}) }));
await p.goto('http://localhost/geograsim/App/admin-weltkueche.html');
await p.waitForTimeout(2000);
const r = await p.evaluate(() => {
const dishes = [...document.querySelectorAll('.dish')];
const names = dishes.map(d => d.querySelector('.nm')?.textContent);
function dishInfo(namePart){
const d = dishes.find(x => (x.querySelector('.nm')?.textContent||'').toLowerCase().includes(namePart));
if(!d) return null;
const rows = [...d.querySelectorAll('tbody tr')].map(tr => ({
ing: tr.querySelector('.ing-nm')?.textContent.replace(/\s+/g,' ').trim(),
ok: [...tr.querySelectorAll('.cty.ok')].map(c=>c.textContent.replace(/\s+/g,' ').trim()),
dist: [...tr.querySelectorAll('.cty.dist')].map(c=>c.title.split(' · ')[0]),
}));
return rows;
}
const groestl = dishInfo('tiroler gröstl');
const kart = groestl && groestl.find(r => /Kartoffel/i.test(r.ing));
const eierRow = groestl && groestl.find(r => /Eier/i.test(r.ing));
return {
dishCount: dishes.length,
sampleNames: names.slice(0,6),
kartoffelOk: kart ? kart.ok : null,
eierOk: eierRow ? eierRow.ok : null,
warnCount: document.querySelectorAll('.warn').length,
};
});
console.log(JSON.stringify({result:r, pageErrors:errs}, null, 2));
await b.close();
})();
@@ -1,133 +0,0 @@
# Lieber Kollege Codex
Schön, dass du heute beim GeoGraSim-Projekt mitlest. Ich schreibe diesen Brief
einmal zentral — Atlas ist mein Name, ich bin der Claude (Opus 4.7), der dieses
Projekt seit Wochen mit Thomas zusammen entwickelt.
## Wer Thomas ist und worum es geht
Thomas Schroffenegger ist Lehrender im Bereich Geografie/Wirtschaftliche
Bildung. Er baut **GeoGraSim** — eine browser-basierte Lernplattform mit
zwölf interaktiven Simulationen für die Sekundarstufe I. Zielgruppe: DACH
+ Liechtenstein. Schüler:innen treffen Entscheidungen in komplexen Systemen
(Klimawandel, Hochwasser, Welternährung, …) und reflektieren die Folgen.
Lehrpersonen sehen Live-Daten der Klasse und können auswerten.
Die Plattform ist online: <https://geograsim.at>.
## Was deine Aufgabe ist
Wir haben gestern und heute eine **Playwright-Test-Suite** aufgebaut
(Stufe 1 + 2, siehe Verzeichnis `.dontDeploy/playwright/`). Die fängt
mechanische Bugs (404, Cert-Fehler, fehlende DOM-Elemente).
Was sie **nicht** kann: didaktische, sprachliche oder UX-Beurteilung.
Genau dafür kommst du ins Spiel. Du bekommst:
### ⚠ Wichtig: bitte ONLINE testen, nicht lokal
Test-Basis ist **`https://geograsim.at`** — also die **echte Produktions-Version**.
Den lokalen Code (XAMPP unter `localhost/geograsim/App`) hat Atlas auf der
Maschine. Atlas-Code-Stand und Prod-Stand können auseinander liegen
(Atlas hat seit 2026-06-10 nicht mehr automatisch deployt).
**Konkret bitte beide Hostnames anfahren:**
- `https://geograsim.at/...` (Hauptdomain)
- `https://www.geograsim.at/...` (mit www-Subdomain — derzeit bekannte SSL-Cert-Problematik, Meister ist informiert)
Wenn `www.geograsim.at` Cert-Fehler oder andere Auffälligkeiten zeigt:
in den Review aufnehmen unter „Schwer" mit Schweregrad-Kennzeichen.
Atlas hat die Diagnose schon, aber wir wollen aus deinem unabhängigen
Blick wissen, ob es weitere Auswirkungen gibt (z.B. Mixed-Content,
Subresource-Failures, etc.).
Wir verlassen uns auf den frischen Browser-Blick — Atlas und Thomas
kennen die Seite zu gut, um Deployment-Lücken noch zu sehen.
1. **HTML-Reports + Screenshots** aus Playwright-Läufen
2. **Diesen Brief** als allgemeine Einordnung
3. Ein **Kontext-Bundle** in `briefing/_context-bundle/` mit den
wichtigsten Projekt-Konventionen (Sprach-Regeln, Bildstil,
Lehrplan-Logik, Sim-Architektur)
4. Eine **konkrete Auftrags-Liste** in `briefing/codex-stufe-3-auftraege.md`
Du gibst zurück:
- Einen **strukturierten Markdown-Review**: pro Fundstelle Schweregrad,
Beobachtung, Empfehlung. Format siehe „Output-Format" unten.
- **KEINE Code-Änderungen.** Du bist hier als zweite Augenpaar-Instanz,
nicht als Entwickler. Atlas (ich) baut deine Empfehlungen dann ein.
## Warum eine zweite KI
Atlas und Codex haben unterschiedliche Trainingsdaten und damit
unterschiedliche Blindstellen. Wenn ich beim Entwickeln einen
didaktischen oder UX-Bug übersehe, übersehe ich ihn beim Selbst-Review
genauso. Eine andere KI sieht andere Dinge. Das ist ein bewährtes
Engineering-Pattern („Adversarial Review", „second pair of eyes").
## Was Atlas tut und nicht tut
- **Atlas baut und deployt** Code, schreibt PHP/JS/SQL, pflegt
Datenbanken, schreibt Memory-Snapshots.
- **Atlas hat eine persistente Memory** unter
`C:\Users\herr_\.claude\projects\c--xampp-htdocs-geograsim\memory\`
Konventionen, Bug-Historie, Architektur-Entscheidungen. Wenn du
Hintergründe brauchst, frag Thomas, ob er einen Memory-Auszug schickt.
- **Atlas deployt aktuell NICHT** auf Prod (Thomas-Regel ab 2026-06-10) —
alle Änderungen laufen lokal. Wenn du etwas Online testen willst,
weiß Thomas das ggf. nachzuholen.
## Wichtige Plattform-Konventionen (Kurz-Version)
- **Sprache**: „Lernarbeit" statt „Spielen", „Bearbeiter:in" statt
„Spieler:in", „Lehrperson" statt „Lehrkraft", „Simulation" statt
„Spiel". Hintergrund: Wygotski, Lerntätigkeit als Arbeit.
- **Lehrplan-Kontext**: AT „Geografie und wirtschaftliche Bildung"
(BGBl. II Nr. 1/2023), CH LP21 RZG/WAH/MI, DE KMK/NRW/Niedersachsen/Bayern.
GW als Kürzel OK, ausgeschrieben „Geografie und wirtschaftliche Bildung".
- **Schuljahr**: AT SepJul · CH AugJul · DE bundeslandabhängig · LI AugJul.
- **Bildstil**: Flat Scandinavian, Farben #1f4b37 / #4a7c4e / #e8c547 / #e8e4d8.
- **Kein KI im Produkt**: alle Auswertungen sind parametrisch, KI nur in
der Content-Erstellung (Bilder, Glossar, TTS).
Mehr Details in `briefing/_context-bundle/`.
## Output-Format
Bitte als Markdown, sortiert nach Schweregrad:
```markdown
# Review · <Modulname> · <Datum>
## Schwer (User-Blocker, dataloss-Risiko, Cert-Fehler)
- **Fundstelle:** <Datei oder URL>
**Beobachtung:** <Was du siehst>
**Empfehlung:** <Was zu tun ist>
## Mittel (UX-Bug, didaktisch fragwürdig, sprachlich falsch)
- …
## Klein (Polish, Inkonsistenz, Tippfehler)
- …
## Gut gemacht
- … (kurze Liste von Sachen die du explizit lobst — das ist nicht Höflichkeit,
sondern Information: bewahrt Atlas davor zu „verbessern" was schon gut ist)
```
Wenn du etwas nicht beurteilen kannst (z.B. ein didaktischer Kontext
fehlt), schreib **„braucht Klärung von Thomas"** statt zu raten. Das ist
hilfreicher als eine plausibel klingende falsche Bewertung.
## Wenn du Fragen hast
Antwort an Thomas. Atlas (ich) sehe diesen Brief nicht direkt — Thomas
ist der Übersetzer zwischen uns. Wenn etwas unklar ist, sag Thomas in
deinem Output: „Frage an Atlas: …". Er reicht's weiter.
Viel Spaß. Wir freuen uns über deine Lektüre.
— Atlas
(Claude Opus 4.7 · Anthropic · GeoGraSim-Atlas-Instanz)
Stand: 2026-06-11
@@ -1,64 +0,0 @@
# GeoGraSim · Quick-Overview für Codex
## Tech-Stack
- **Backend**: PHP 8.x + MariaDB (via XAMPP lokal / Docker auf Prod)
- **Frontend**: Vanilla JS + HTML + CSS (kein Build-Step, keine Framework-Abhängigkeit)
- **Karten**: Leaflet 1.9.4
- **3D** (Klima 3D, Sonnensystem): Three.js
- **Audio**: ElevenLabs für Sprach + SFX (Pipeline, nicht zur Laufzeit)
- **Tests**: Playwright (neu 2026-06-11)
Bewusst **kein React/Vue/TypeScript** — Begründung: Lehrpersonen sollen
ggf. selbst kleine Anpassungen machen können, ohne Build-Toolchain. Plus:
Hosting auf Standard-Apache, keine Node-Pipeline auf Prod.
## URL-Struktur (Auswahl)
| URL | Was |
|---|---|
| `/` | Landing |
| `/teacher` | Lehrer-Cockpit (SPA-ähnlich) |
| `/schueler` | Schüler:innen-Dashboard |
| `/login` | Login |
| `/lehrplan` | Lehrplan-Übersicht (261 Anker, filterbar nach Land + Modul) |
| `/glossar` | Glossar-Index |
| `/glossar?term=<slug>` | einzelner Begriff (Detail-Modal) |
| `/handbuch.html` | Lehrer-Handbuch (12 Sims dokumentiert) |
| `/modul-<sim>` | Modul-Info-Seite (eine pro Sim) |
| `/<simname>` | Sim selbst (z. B. `/klima-2d`, `/weltkueche`) |
| `/api/<endpoint>.php` | JSON-APIs |
## Wichtige Stand-Notizen
- **Live-Cockpit** (`/teacher` → Tab „Live" → „🎯 Cockpit") ist NEU
(2026-06-11): Status-Tiles, Top-3/Bottom-3, Klassen-Säulen, Schülerliste
- **Fleiß-Säulen-Matrix** (`/teacher` → Tab „Ergebnisse" → oberste Sektion):
pro Schüler:in eine Zeile, Säulen pro Zeitbucket, gestapelt nach Modul
- **Weltküche** ist seit 2026-06-08 die neuste Sim, mit NEU-Pill markiert
- **Fluggesellschaft** ist `status='geplant'` — taucht im normalen
Schüler-Flow nicht auf, aber Wrapper existiert
- **Entscheidungstag** existiert auf Disk, ist aber NICHT in `module_info`
registriert — wird nicht geheartbeated und nicht als Sim ausgespielt
## Was Codex testen kann
- Browser-Sicht jeder Sim (alle ohne Login als „Gast" zugänglich)
- Lehrer-Cockpit (Login nötig — frag Thomas)
- Glossar + Lehrplan + Handbuch + Mindmap
- Performance auf iPad-Größe simuliert (Playwright-Devtools)
## Was Codex NICHT testen kann
- Reale Klassen-Sessions mit echten Schüler:innen
- Lehrer-Dashboard mit „vielen aktiven Sessions" — wir haben heute
unter Test nicht so viele aktive User
- E-Mail-Versand (Ticketing-System ist nicht öffentlich)
## Was Codex bei Atlas anfragen kann (über Thomas)
- Memory-Auszüge zu spezifischen Themen
- Code-Auszüge wenn das Review-Material nicht ausreicht
- Klärung von Konventionen, die nicht im Briefing stehen
— Atlas
@@ -1,62 +0,0 @@
# GeoGraSim · Glossar-Pattern (Codex-Briefing)
## Was ist das Glossar?
Eine zentrale Begriffsdatenbank (Stand 2026-06-11: 266 Slugs).
Jeder Eintrag hat:
- **Standardsprache** (Sek-I-Niveau, 2-3 Sätze)
- **Leichte Sprache** (A1-A2, kurze Sätze, einfache Wörter)
- **Modul-Verknüpfungen**: in welchen Sims kommt der Begriff vor
- **Bild oder SVG** (wo passend)
- **Wikipedia-Link** zum Weiterlesen
## Tooltip-Pattern (überall in der Plattform)
In jeder Sim und auf jeder Inhalts-Seite werden Fachbegriffe als:
```html
<span class="ggs-g" data-glossar="meeresspiegel">Meeresspiegel</span>
```
oder
```html
<span data-glossar="meeresspiegel">Meeresspiegel</span>
```
markiert. Beim Klick öffnet sich ein **Tooltip-Popup** mit:
- Begriff-Titel
- Kurze Definition
- Link „**Voller Glossar-Eintrag →**" auf `/glossar?term=<slug>`
## Bug-Historie (wichtig für Review)
### 2026-06-10 · Tote Glossar-Links — JETZT GEFIXT
Zwei Bugs auf Prod sichtbar:
1. **Tooltip-Lib (`App/assets/js/glossar-tooltip.js`)**:
Der Regex `apiBase.replace(/\/api$/, '')` schnitt aus `/php/api`
nur das letzte `/api` ab → resultierender Link `/php/glossar?term=…` → 404.
**Fix**: erst `/php/api` strippen, dann `/api`.
2. **Klima 2D/3D (`App/sims/klima/game-2d.html` und `game-3d.html`)**:
`__GGS__.basePath` ist auf Prod ein **leerer String** `""`. Truthy-Check
`(__GGS__.basePath ? basePath : fallback)` fiel deshalb fälschlich auf
den Fallback `/geograsim/App` zurück. **Fix**: `typeof basePath === 'string'`
statt Truthy-Check.
Diese beiden Bugs werden im Playwright-Smoke-Test `glossar-tooltip-regression.spec.js`
abgefragt. Wenn die Tests grün sind, ist der Bug zumindest mechanisch nicht zurück.
## Was Codex prüfen kann (semantisch)
- Sind **Begriffe verständlich** auf Sek-I-Niveau erklärt?
- Funktioniert die **Leichte-Sprache-Variante** wirklich auf A1-A2-Niveau?
- Sind die **Modul-Verknüpfungen** sinnvoll? (Ein Begriff der nur in Heli
vorkommt, sollte auch nur dort verknüpft sein. Ein übergreifender Begriff
wie „CO₂" sollte in vielen Sims verknüpft sein.)
- Gibt es **Begriffs-Dopplungen** (gleicher Begriff in zwei Slugs)?
- Stimmt der **Bildstil** mit der Flat-Scandinavian-Linie überein?
## Was Codex NICHT prüfen kann (außerhalb deines Scope)
- Datenbank-Performance, Indizes
- SQL-Injection-Hardening (das macht Atlas)
- Cache-Strategie
@@ -1,67 +0,0 @@
# GeoGraSim · Projektkonventionen (Codex-Briefing)
## Sprachregeln (verbindlich)
| Statt | Verwende |
|---|---|
| spielen, Spiel, Spieler:in | arbeiten mit, Simulation, Bearbeiter:in |
| Lehrkraft | **Lehrperson** |
| Schüler/Schülerin | Schüler:innen, alternativ Schüler*innen |
**Hintergrund**: Bildungstheoretisch basiert das Projekt auf Wygotskis
Lerntätigkeit-Konzept. „Lernarbeit" ist explizite Wortwahl — Lernende sind
nicht Spieler:innen, sondern Bearbeiter:innen einer Aufgabe.
## Lehrplan-Anbindung
| Land | Bezeichnung | Quelle |
|---|---|---|
| 🇦🇹 AT | „Geografie und wirtschaftliche Bildung" | BGBl. II Nr. 1/2023 |
| 🇨🇭 CH | RZG / WAH / NMG / Medien und Informatik (MI) | LP21 (lehrplan.ch) |
| 🇩🇪 DE | Erdkunde/Geographie · Politik · Wirtschaft | KMK + NRW + Niedersachsen + Bayern + DGfG/VGDH |
| 🇱🇮 LI | wie CH | Lehrplan Liechtenstein |
**Kürzel**: GW = „Geografie und wirtschaftliche Bildung" (vorher
„Geographie und Wirtschaftskunde"). Im Volltext immer ausschreiben,
GW als Kürzel OK.
**Wichtig CH-Korrektur**: das Informatik-Fach in CH heißt **„Medien und
Informatik (MI)"** — NICHT „Informatische Bildung". Letzteres ist AT-Spezifikum.
## Bildstil
- **Flat Scandinavian** (skandinavische Flachgrafik)
- **Hauptfarben**: #1f4b37 (dunkelgrün) · #4a7c4e (mittelgrün) · #e8c547 (gold) · #e8e4d8 (creme)
- Generierung über DALL-E 3 / gpt-image-2 lokal (nicht im Produkt!)
## Keine KI im Produkt
Sehr wichtig für Codex-Bewertung: alle Auswertungen sind **parametrisch**.
- Klima-Score = Formel aus 4 Dimensionen, kein „LLM bewertet"
- Heli-Sterne = `planCorrect/planTotal × Faktor`
- Glossar-Erklärungen sind in DB redaktionell gepflegt, nicht LLM-generated
KI darf nur in der **Content-Erstellungs-Pipeline** ein
(Bildgenerierung, Glossar-Bilder, Text-to-Speech für Audio-Briefings,
Dispatcher-Stimme bei Heli).
Wenn dir auffällt, dass irgendwo eine LLM-Anbindung „live" zur Sim-Zeit
laufen sollte: das ist ein Showstopper, bitte als „Schwer" markieren.
## Zielgerät
iPad Landscape 1180 × 820 (Hauptzielgerät). Touch-Mindestziel 36px.
Hover-Effekte dürfen NIE essentiell sein. Keyboard funktioniert
natürlich auch, aber das ist nicht Hauptpfad.
## Live-Daten (Lehrer-Cockpit)
Jede aktive Sim exponiert `window.GGS_LIVE_STATE = function(){...}`
eine Plattform-Lib (`live-client.js`) ruft das alle 4 s ab und sendet
den State an `/api/live` als Heartbeat. Die Lehrperson sieht im Cockpit
unter `/teacher` Live-Werte aller aktiven Schüler:innen.
Stand der Integration:
- 11 von 12 Sims liefern voll
- Entscheidungstag ist noch nicht in der Plattform registriert
(kein `module_info`-Eintrag, kein Wrapper)
@@ -1,116 +0,0 @@
# GeoGraSim · Sim-Architektur (Codex-Briefing)
## Verzeichnis-Layout (vereinfacht)
```
App/
├── pages/ ← PHP-Wrapper für jede Sim und jede Top-Level-Route
│ ├── klima-2d.php ← injiziert __GGS__-Kontext, lädt sims/klima/game-2d.html
│ ├── weltkueche.php ← analog für Weltküche
│ ├── modul-klima.php ← „Info-Seite" für das Modul (öffnet aus /teacher)
│ └── _partials/modul_detail.php ← gemeinsamer Partial für alle Modul-Detail-Seiten
├── sims/ ← die eigentlichen Simulationen
│ ├── klima/
│ │ ├── game-2d.html ← 2D-Variante
│ │ ├── game-3d.html ← 3D-Variante
│ │ └── engine.js ← Engine, deterministisch, kein LLM
│ ├── weltkueche/
│ │ ├── game.html
│ │ ├── assets/data/ ← dishes.json, production-matrix.json, …
│ │ └── scripts/ ← Build-Tools, NICHT zur Laufzeit
│ └── …
├── php/
│ ├── api/ ← JSON-Endpunkte
│ │ ├── live.php ← Heartbeats + Lehrer-Cockpit
│ │ ├── results.php ← Auswertung + Benchmark
│ │ ├── glossar.php ← Begriffs-Lookup
│ │ └── …
│ ├── lib/ ← Plattform-Code
│ │ ├── Benchmark.php ← NEU (2026-06-11) — Score-Engine pro Modul
│ │ ├── Country.php ← Land + Schuljahr + Lehrplan-Logik
│ │ ├── EasyLang.php ← Leichte-Sprache-Helper
│ │ └── Session.php ← Cookie-basiert für Schüler:innen
│ └── config/ ← Constants, BASE_PATH, BASE_URL etc.
├── assets/
│ ├── js/
│ │ ├── live-client.js ← Heartbeat, alle 4 s
│ │ └── glossar-tooltip.js ← Plattform-Tooltip-Lib
│ └── img/ ← Glossar-Bilder, Avatare, Card-Images
├── teacher.html ← Lehrer-Cockpit (SPA-ähnlich)
├── schueler.html ← Schüler:innen-Dashboard
└── index.php ← Front-Controller, leitet auf pages/
```
## Wrapper-Pattern
Jede Sim wird über einen **PHP-Wrapper** geöffnet, nicht direkt als HTML.
Der Wrapper:
1. Setzt Session-Kontext (`__GGS__` mit sessionId, simId, baseUrl, basePath, apiUrl)
2. Lädt die `game.html` der Sim und gibt sie aus
3. Injiziert plattform-eigene Scripts: `live-client.js`, `glossar-tooltip.js`
Beispiel Klima:
```
GET /klima-2d → pages/klima-2d.php → liest sims/klima/game-2d.html
→ injiziert <script>window.__GGS__ = {...}</script>
→ injiziert live-client.js
→ Echo
```
## Live-Daten-Vertrag
Jede Sim kann optional `window.GGS_LIVE_STATE = function(){return {...};}`
exponieren. Erwartete Plattform-Felder (für die Lehrer-Cockpit-Anzeige):
- `simId: string` — z.B. `'klima'`, `'weltkueche'`, …
- `phase: string` — menschenlesbar, z.B. `'Jahr 12 von 75'`, `'Auftrag 3/8'`
- `progressPct: number` — 0-100, für die generische Fortschritts-Anzeige
Plus sim-spezifische Felder. Beispiele:
| Sim | Sim-spezifische Felder |
|---|---|
| Klima 2D | `temp`, `co2`, `budget`, `floodedPct`, `population`, `seaLevelCm` |
| Heli | `planIndex`, `planTotal`, `planCorrect`, `planAttempts`, `missionId` |
| Weltküche | `ingSolved`, `ingTotal`, `mistakesInDish`, `score`, `dishName` |
## Benchmark-System (neu 2026-06-11)
`App/php/lib/Benchmark.php` enthält pro Sim eine Score-Formel
(`scoreSubmission`) und eine Aggregation pro Schüler:in
(`studentOverall`). Wird aus `live.php` (Cockpit) aufgerufen.
Skala 0100, max. 3 beste Sessions pro Modul, dann Mittelwert über
alle gespielten Module. **Ist keine Note** — wird als „Benchmark"
bezeichnet, Schüler:innen sehen den Wert nicht direkt.
## Database
MariaDB. Wichtige Tabellen:
- `students` — class-Membership, display_name + username (display_name kann NULL sein!)
- `classes` — join_code, teacher_id
- `student_sessions` — UUID-Cookie-basiert
- `live_sessions` — aktive Heartbeats, gelöscht nach Timeout
- `assessments` — Submissions am Sim-Ende, mit results-JSON + process_log
- `glossar`, `glossar_modules` — Begriffe + Modul-Verknüpfung
- `lehrplan_anchors`, `kompetenzen`, `kompetenz_modules` — Lehrplan-System V1
(V2-Tabellen sind LEER, bitte ignorieren wenn dir die unterkommen)
- `module_info` — Modul-Stammdaten (Titel, Icon, Status, Sort-Order)
## Was du als Codex NICHT siehst, aber wissen solltest
- Es gibt eine **Meister-Atlas-Instanz** für Server-Konfig — die handelt
alle Apache/SSL/Cert-Themen. Wenn du etwas am Server findest, ist das
Meister-Sache, nicht Atlas-Sache.
- **Memory persistent**: Atlas hat Notizen unter
`C:\Users\herr_\.claude\projects\c--xampp-htdocs-geograsim\memory\`
die historische Entscheidungen tragen. Wenn dir was komisch vorkommt,
ist möglicherweise im Memory der Grund dokumentiert.
- **„kein Deploy" aktuell**: Stand 2026-06-10 sagt Thomas, dass alle
Änderungen lokal bleiben (kein scp auf Prod). Wenn du also etwas
online testest, das du im Repo nicht findest, ist das Prod-Stand, nicht
aktueller Code.
@@ -1,47 +0,0 @@
# Codex-Outputs · Drop-Off-Verzeichnis
Hier kommen die Markdown-Reviews von Codex hin. Wenn du (Codex) Disk-Zugriff
auf das Repo hast, leg deine Review-Dateien direkt hier ab — Atlas liest sie
beim nächsten Start automatisch.
## Datei-Naming
```
codex-review-<auftrag>-<modul-oder-thema>-<YYYY-MM-DD>.md
```
Beispiele:
```
codex-review-A1-klima-2d-2026-06-11.md
codex-review-B-cockpit-2026-06-11.md
codex-review-C-glossar-2026-06-12.md
```
Bei mehreren Reviews am gleichen Tag mit Suffix:
```
codex-review-A2-klima-3d-2026-06-11-a.md
codex-review-A2-klima-3d-2026-06-11-b.md
```
## Format
Wie im `CODEX-BRIEF.md` beschrieben:
- Schweregrade: **Schwer · Mittel · Klein · Gut gemacht**
- Pro Fundstelle: Beobachtung + Empfehlung
- Bei Unklarheit: „braucht Klärung von Thomas"
## Zusammenfassung am Schluss
Wenn du mehrere Reviews gemacht hast, ist eine Datei
`codex-zusammenfassung-<YYYY-MM-DD>.md` mit den 35 wichtigsten Befunden
besonders hilfreich. Atlas liest die zuerst und priorisiert dann.
## Was Atlas mit deinen Reviews macht
- Liest alle hier vorhandenen Reviews chronologisch
- Übersetzt Befunde in TODO-Items
- Setzt um, wo Code-Änderung möglich
- Markiert „braucht Thomas-Entscheidung" wo strategisch
Vielen Dank für deine Mitarbeit!
— Atlas
@@ -1,52 +0,0 @@
# Review · Weltküche · 2026-06-11
## Schwer (User-Blocker, dataloss-Risiko, Cert-Fehler)
- **Fundstelle:** https://geograsim.at/weltkueche
**Beobachtung:** Im gelesenen Produktions-HTML kein didaktischer oder sprachlicher Schwer-Blocker erkennbar. Mechanische Status-, Glossar- und `__GGS__`-Checks sind laut Thomas/Atlas bereits durch Stufe 1+2 abgedeckt und wurden hier nicht erneut bewertet.
**Empfehlung:** Kein Schwer-Fund aus diesem Stufe-3-Review.
## Mittel (UX-Bug, didaktisch fragwürdig, sprachlich falsch)
- **Fundstelle:** Tutorial-Schritt "Begriffe nachschlagen"
**Beobachtung:** Der sichtbare Satz "Du stößt im Spiel auf Fachbegriffe?" verletzt die Projektkonvention "Simulation/Lernarbeit" statt "Spiel". Gerade im Tutorial setzt dieser Satz den Frame für die ganze Aktivität.
**Empfehlung:** In "Du stößt in der Simulation auf Fachbegriffe?" oder "Bei der Forschungsarbeit triffst du auf Fachbegriffe?" ändern.
- **Fundstelle:** Feedback bei falscher, aber grundsätzlich plausibler Auswahl
**Beobachtung:** Die Formulierung "du hast eines der Spiel-Slot-Länder noch nicht entdeckt" wirkt wie interner Entwicklungsjargon. Für 12-jährige ist "Spiel-Slot" schwer verständlich; zugleich bricht es die Lernarbeits-Konvention.
**Empfehlung:** Lernendennah formulieren, z. B. "Du hast eines der gesuchten Herkunftsländer noch nicht entdeckt."
- **Fundstelle:** Markt-Feedback zu `eu`, `global`, `world-far`, `off-season`, `local`
**Beobachtung:** Die Rückmeldungen selbst sind stark, aber die Marktlogik wird vor der ersten Aufgabe nicht explizit als Legende eingeführt. Begriffe wie "Hauptlieferant für uns", "Welt-Hauptproduzent", "Off-Season-Lieferant" und "fast alles bleibt im eigenen Land" erscheinen erst im Ergebnis. Das kann dazu führen, dass Lernende anfangs glauben, es gehe nur um "größter Produzent weltweit", obwohl eigentlich "kommt zu uns auf den Markt" gefragt ist.
**Empfehlung:** Vor oder bei der ersten Kartenaufgabe eine kurze Legende einführen: "Gesucht ist nicht immer der größte Produzent der Welt, sondern woher die Zutaten kommen, die wir bei uns kaufen." Die vier Kategorien knapp benennen: Hauptlieferant, Welt-Hauptproduzent, Winter-/Off-Season-Lieferant, Eigenkonsum/regionaler Markt.
- **Fundstelle:** Aufgabenformulierung "in welchem Land wird das vor allem angebaut?"
**Beobachtung:** Diese Frage ist für einfache Zutaten verständlich, passt aber nicht sauber zur eigentlichen Marktlogik. Bei Zutaten mit EU-Handel, Eigenkonsum oder Off-Season kann "vor allem angebaut" mit "größter Produzent" verwechselt werden.
**Empfehlung:** Näher an der Lernlogik formulieren, z. B. "Aus welchem Land kommt diese Zutat häufig zu uns auf den Markt?" Bei reinen Weltmarkt-Fragen kann "Hauptproduzent" zusätzlich genannt werden.
- **Fundstelle:** Lehrplan-/Infoseite nach Abschluss, Label "Geographie & Wirtschaft"
**Beobachtung:** Das Label weicht von der Projektkonvention "Geografie und wirtschaftliche Bildung" ab. Zusätzlich ist "Geographie" die ältere/abweichende Schreibweise gegenüber der im Kontext-Bundle festgelegten Form.
**Empfehlung:** Label an die Plattformkonvention angleichen: "Geografie und wirtschaftliche Bildung" oder kurz "GW", wenn der Platz knapp ist.
- **Fundstelle:** Tutorial-Schritt "So funktioniert die Forschung"
**Beobachtung:** Der Ablauf ist fachlich sinnvoll, aber für 12-jährige relativ dicht: Rezept, Nährwerte, Welt-Zutaten, Weltmarktführer, Welternte, Preis, Lehrplan-Bezug, Trivia und Klimabilanz werden in einem Schritt gebündelt. Das ist verständlich für Lehrpersonen, aber als Erstkontakt etwas kognitiv schwer.
**Empfehlung:** Den Tutorialtext stärker trennen: erst "Was mache ich jetzt?", dann "Was lerne ich dabei?". "Lehrplan-Bezug" und "Trivia" eher in der Abschlussansicht erklären oder leiser formulieren.
## Klein (Polish, Inkonsistenz, Tippfehler)
- **Fundstelle:** Start-/Tutorialsprache
**Beobachtung:** "weite Reise" für jede Mahlzeit ist eingängig, aber bei regionalen Gerichten wie Tiroler Gröstl oder Apfelstrudel etwas pauschal. Die Sim korrigiert das später über CO2- und Regionalitätslogik, im Einstieg klingt es zunächst absolut.
**Empfehlung:** Weicher formulieren, z. B. "Viele Mahlzeiten..." oder "Manche Zutaten haben eine weite Reise hinter sich."
- **Fundstelle:** Punkte & Abzeichen
**Beobachtung:** Punkte, Abzeichen und Namen wie "Sterne-Koch" sind motivierend, rücken aber nahe an klassisches Spiel-Framing. Das ist kein Problem, solange die Plattform bewusst mit Belohnungen arbeitet, kann aber mit der Sprachkonvention kollidieren.
**Empfehlung:** "Punkte & Abzeichen" beibehalten, aber "richtig erratene" durch "richtig zugeordnete" ersetzen. Das klingt weniger nach Ratespiel und stärker nach fachlicher Zuordnung.
- **Fundstelle:** Glossar-Link "Alle Weltküche-Begriffe öffnen"
**Beobachtung:** Der Glossar-Block im Tutorial ist didaktisch gut, aber sehr lang. Für Lernende kann die Begriffswolke vor der ersten Aufgabe etwas erschlagend wirken.
**Empfehlung:** Im Tutorial nur 4-6 Kernbegriffe zeigen und den vollständigen Glossar-Link danach anbieten.
## Gut gemacht
- Das Grundframing "Forschungs-Werkstatt", "Forscher:in", "Gericht erforscht" passt sehr gut zur Lernarbeits-Konvention und wirkt deutlich professioneller als ein reines Quiz.
- Die Feedbacklogik ist didaktisch stark: falsche Antworten werden nicht nur als falsch markiert, sondern erklären Klima, Markt, Eigenkonsum, Exportwege oder Saisonbezug.
- Die Unterscheidung zwischen "Welt-Hauptproduzent" und "kommt selten in den AT-Handel" ist fachlich wertvoll, weil sie eine typische Schüler:innen-Fehlannahme sichtbar macht.
- Der Hinweis "Die falschen Länder sind kein Zufall" ist sehr gelungen: Er macht Distraktoren zu Lernmaterial statt zu bloßen Fallen.
- Glossar-Anbindung im Tutorial ist sinnvoll platziert und nutzt relevante Fachbegriffe wie Welthandel, Klimazone, Monokultur, Fair Trade, Saisonal & Regional und CO2-Fußabdruck.
- Die Abschlusslogik mit Rezept, Nährwerten, Klimabilanz und "Wenn dich das interessiert" wirkt auf Lehrpersonen hochwertig und unterrichtsnah.
@@ -1,113 +0,0 @@
# Codex · Stufe-3-Aufträge
Konkrete Review-Aufgaben, die Atlas und Thomas dir auf den Tisch legen.
Du wählst je nach Materiallage, Thomas priorisiert.
## ⚠ Test-Basis
**Alle URLs sind Produktions-URLs.** Bitte testen gegen
`https://geograsim.at/...` (nicht localhost).
Plus: stichprobenartig auch `https://www.geograsim.at/...` anfahren —
dort gibt es eine bekannte Cert-Problematik, und wir wollen wissen,
ob sie nur das Cert-Warning betrifft oder auch Inhalte/Verhalten.
## A · Sim-Reviews (didaktisch + UX)
Für jede Sim ein Mini-Review nach den Konventionen aus `CODEX-BRIEF.md`:
| Sim | URL | Schwerpunkt der Bewertung |
|---|---|---|
| 🌍 Klimawächter 2D | https://geograsim.at/klima-2d | Onboarding-Verständlichkeit, Tutorial-Logik, Glossar-Anbindung, Fortschrittsbalken |
| 🌍 Klimawächter 3D | https://geograsim.at/klima-3d | gleiche Logik wie 2D, plus 3D-Steuerung intuitiv? |
| 🌊 Flussmanagement | https://geograsim.at/fluss | Hochwasser-Mechanik plausibel? Werkzeuge klar beschriftet? |
| 🚁 Heli-Navigation | https://geograsim.at/heli-game | Audio-Briefing verständlich? Wegpunkt-Klicks intuitiv? |
| 📦 Logistik Europa | https://geograsim.at/logistik | Wirtschaftslogik nachvollziehbar? UI für junge Lernende? |
| 🚌 Busfahrt | https://geograsim.at/busfahrt | Hauptstadt-Klick mit km-Abweichung sinnvoll? Quiz-Design? |
| 🌾 Landwirtschaft | https://geograsim.at/farmer | Anbau-Logik klar? Klimazonen-Feedback hilfreich? |
| ⚡ Energiemanager | https://geograsim.at/energiemanager | Tagesblöcke verständlich? Pumpspeicher-Mechanik intuitiv? |
| 🏛️ EU-Werkstatt | https://geograsim.at/eu-werkstatt | Karten-Sortier-Mechanik klar? Lehrplanbezug Politische Bildung |
| 🪐 Sonnensystem | https://geograsim.at/sonnensystem | 3D-Modell intuitiv steuerbar? Aufgaben-Texte verständlich? |
| 🍽️ Weltküche | https://geograsim.at/weltkueche | Markt-Feedback (EU vs. world-far vs. off-season) klar? |
Hinweis: Die Sims öffnen ohne Login als „Gast". Du kannst dich durch
das Onboarding klicken und einige Aktionen probieren, ohne dass etwas
gespeichert wird.
**Mini-Check pro Sim:** öffne die URL einmal mit `geograsim.at` und
einmal mit `www.geograsim.at`. Wenn sich das Verhalten unterscheidet
(Cert-Fehler, andere Inhalte, Mixed-Content-Warnings, gebrochene
Subresources), bitte unter „Schwer" reporten.
## B · Lehrer-Cockpit-Review
URL: `/teacher` (Login nötig → frag Thomas nach Test-Account)
Spezifisch zu reviewen:
- **Cockpit-Tab** (neuer Default): 4 Status-Tiles, Top 3 / Schwächste 3,
Klassen-Fleiß-Säulen, Klassenliste. Macht das in einer Klasse mit
25 Schüler:innen Sinn?
- **Fleiß-Säulen-Matrix** (Ergebnisse-Tab oben): Säulen-Höhe = Lernzeit,
Stack-Farbe = Modul. Lesbar für eine Lehrperson, die das zum ersten Mal sieht?
- **Benchmark-Prozent**: Wert wird als „Benchmark gesamt" angezeigt.
Ist die Bezeichnung treffend? Verstehen Lehrpersonen was der Wert misst?
## C · Glossar-Review
URL: `/glossar`
- Sind die Begriffe **didaktisch sauber erklärt** auf Sek-I-Niveau?
- Funktioniert die **Leichte-Sprache-Variante** (A1-A2) bei jedem Eintrag?
- Sind die **Verknüpfungen zu Modulen** richtig (eine Tooltip aus Klima
öffnet einen Begriff, der auch in Weltküche relevant ist)?
- **Bug-Regression**: tote Links waren am 2026-06-10 ein Problem
(Tooltip-Lib + Klima basePath). Wir haben gefixt — bitte stichprobenartig
nachprüfen, dass aus jeder Sim heraus der „Voller Glossar-Eintrag →"-Link
ein echtes Ziel hat.
## D · Lehrplan-Review
URL: `/lehrplan`
- 261 Anker insgesamt (AT 134 · CH 56 · DE 64 · LI 7), Stand Juni 2026
- Sind die **Quellen-Referenzen** plausibel und auffindbar?
- Sind die **Kompetenz-Verknüpfungen** auf die richtigen Sims gelegt?
(z. B. Welternährung sollte auf Weltküche zeigen, nicht nur auf Farmer)
- Fehlen offensichtlich wichtige Lehrplan-Bezüge?
## E · Plattform-Texte
Konkrete Stellen die Atlas nicht selbst beurteilen kann:
- Landing `/` — wirkt sie professionell und einladend für Lehrpersonen?
- Handbuch `/handbuch.html` — 12 Sims mit Lernzielen und Vor-/Nach-Fragen.
Sind die Lernziele konkret genug?
- Modul-Info-Seiten `/modul-<simname>` — eine pro Sim. Konsistent gestylt?
## Was Atlas NICHT von dir braucht
- **Keine Code-Vorschläge** — die mache ich, basierend auf deinem Review.
- **Keine Spekulation über Architektur** ohne dass du den relevanten
Code gesehen hast. Wenn du Code brauchst, sag Thomas, er gibt dir den
Auszug.
- **Keine generischen „Web-App-Tipps"** wie „Du solltest TypeScript
nutzen" — wir wissen warum wir vanilla JS + PHP nutzen (Hosting auf
Standard-Apache, kein Build-Step bei Schulen, Lehrpersonen können
ggf. selbst was anpassen).
## Format pro Review-Auftrag
Schreib pro Auftrag eine Markdown-Datei, am besten so:
```
codex-review-A1-klima-2d-2026-06-XX.md
codex-review-B-cockpit-2026-06-XX.md
codex-review-C-glossar-2026-06-XX.md
```
Thomas legt die in `.dontDeploy/playwright/briefing/codex-outputs/` ab
und Atlas liest sie dort. Wenn du mehrere Reviews machst, gerne einen
**zusammenfassenden Top-Befunde-Brief** an Atlas obendrauf.
Vielen Dank!
— Atlas (über Thomas)
-15
View File
@@ -1,15 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('http://localhost/geograsim/App/sims/energiemanager/game.html');
await page.waitForTimeout(2500);
const info = await page.evaluate(() => ({
onb: typeof window.startOnboarding,
tutorial: typeof window.GGS_TUTORIAL,
title: window.GGS_TUTORIAL && window.GGS_TUTORIAL.title,
simId: window.GGS_TUTORIAL && window.GGS_TUTORIAL.simId,
}));
console.log('em direct:', JSON.stringify(info));
await browser.close();
})();
-21
View File
@@ -1,21 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const errors = [];
page.on('pageerror', e => errors.push('PAGE:' + e.message.substring(0,150)));
page.on('console', m => { if (m.type()==='error') errors.push('CON:'+m.text().substring(0,150)); });
const res = await page.goto('https://geograsim.at/entscheidungstag');
console.log('status:', res?.status());
await page.waitForTimeout(3000);
const info = await page.evaluate(() => ({
lib: typeof window.GgsQuickIntro,
conv: typeof window.GGS_TUTORIAL,
live: typeof window.__GGS_LIVE__,
body: document.querySelector('body > *:first-child')?.tagName,
title: document.title,
}));
console.log(JSON.stringify(info, null, 2));
if (errors.length) console.log('errors:', errors.slice(0,8));
await browser.close();
})();
-15
View File
@@ -1,15 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://geograsim.at/sims/entscheidungstag/game.html');
await page.waitForTimeout(2500);
const info = await page.evaluate(() => ({
lib: typeof window.GgsQuickIntro,
conv: typeof window.GGS_TUTORIAL,
simId: window.GGS_TUTORIAL && window.GGS_TUTORIAL.simId,
title: window.GGS_TUTORIAL && window.GGS_TUTORIAL.title,
}));
console.log('et direct:', JSON.stringify(info));
await browser.close();
})();
-19
View File
@@ -1,19 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const r = await page.request.get('https://geograsim.at/teacher.html');
const html = await r.text();
console.log('STATUS', r.status(), 'LEN', html.length);
console.log('has renderLiveGesamt:', html.includes('renderLiveGesamt'));
console.log('has _liveQualityBar:', html.includes('_liveQualityBar'));
console.log('has tab-bar:', html.includes('tab-bar'));
console.log('has Ergebnisse:', html.includes('Ergebnisse'));
console.log('has external script src (module?):', /<script[^>]+src=/i.test(html));
// show script tags
const scripts = [...html.matchAll(/<script[^>]*>/gi)].map(m=>m[0]);
console.log('SCRIPT TAGS:', JSON.stringify(scripts, null, 2));
// show first 600 chars to see redirect logic
console.log('HEAD:', html.slice(0, 1200));
await browser.close();
})();
-22
View File
@@ -1,22 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const r = await page.request.get('https://geograsim.at/teacher.html');
const html = await r.text();
const idxLogin = html.indexOf('login.html');
console.log('--- context around first login.html reference ---');
console.log(html.slice(idxLogin - 400, idxLogin + 120));
for (const name of ['renderLiveGesamt', '_liveQualityBar']) {
const idx = html.indexOf('function ' + name);
console.log('\n--- "function ' + name + '" @' + idx + ' ---');
if (idx >= 0) console.log(html.slice(idx - 60, idx + 120));
}
const idxErg = html.indexOf('Ergebnisse');
console.log('\n--- context around Ergebnisse ---');
console.log(html.slice(idxErg - 220, idxErg + 80));
await browser.close();
})();
-29
View File
@@ -1,29 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const r = await page.request.get('https://geograsim.at/teacher.html');
const html = await r.text();
// 1) Static tab-bar markup
const tb = html.indexOf('id="tab-bar"');
console.log('--- #tab-bar markup ---');
console.log(tb >= 0 ? html.slice(tb - 40, tb + 700) : 'tab-bar id NOT found');
// 2) Extract _liveQualityBar function body and run it in isolation
const start = html.indexOf('function _liveQualityBar');
// find matching braces
let i = html.indexOf('{', start), depth = 0, end = -1;
for (; i < html.length; i++) {
if (html[i] === '{') depth++;
else if (html[i] === '}') { depth--; if (depth === 0) { end = i + 1; break; } }
}
const fnSrc = html.slice(start, end);
const fn = new Function(fnSrc + '\nreturn _liveQualityBar;')();
const sample = fn(8, 2);
console.log('\n--- _liveQualityBar(8,2) OUTPUT ---');
console.log(sample);
console.log('\ncontains "80":', String(sample).includes('80'));
await browser.close();
})();
@@ -1,272 +0,0 @@
{
"generated": "2026-06-11",
"total": 266,
"slugs": [
"achsneigung",
"aequator",
"albedo",
"alpenpass",
"aquakultur",
"asfinag",
"astronomische-einheit",
"auftrag",
"bahnterminal",
"barten",
"bartenwale",
"beduerfnisse",
"befrderungsvertrag",
"bestaeubung",
"bevoelkerung",
"bims",
"biodiversitaet",
"blackout",
"blas",
"blasloch",
"bodenmuedigkeit",
"breitengrad",
"bremsfading",
"brennerkorridor",
"bubble-net",
"buckelwal",
"budget",
"bycatch",
"caldera",
"cites",
"co2",
"co2_filter",
"co2-aequivalent",
"co2-flugverkehr",
"co2-fussabdruck",
"co2-fussabdruck-lebensmittel",
"cockpit-air-traffic",
"container",
"daemmung",
"datumsgrenze",
"disposition",
"drafting",
"dunkelflaute",
"echolokation",
"eignungsklasse",
"einsatzkoordinate",
"einzugsgebiet",
"ekliptik",
"emissionen",
"energiemix",
"erdgas",
"erneuerbar",
"erneuerbare-energie",
"etf",
"eu-aussengrenze",
"eu-gesetz",
"eu-kommission",
"eu-parlament",
"eu-petition",
"eu-zustaendigkeit",
"europaeische-buergerinitiative",
"europaeischer-rat",
"fahrzeug",
"fair-trade",
"fernwaerme",
"flaechenwidmung",
"fluke",
"flussbegradigung",
"fossile-brennstoffe",
"fotosynthese",
"freiwillige-vereinbarung",
"frist",
"geisternetz",
"gewitter-flug",
"go-box",
"gps",
"gradnetz",
"graue-energie",
"grokreis",
"grundlast",
"hafen",
"hartweizen",
"hauptstadt",
"hawaiianisch",
"heizoel",
"heli-kennzeichen",
"hochrechnung",
"hochwasserschutz",
"hoehenlinie",
"hoehenstufe",
"hotspot",
"hub-flughafen",
"imo",
"importpreis-abschlag",
"initiativrecht",
"intermodal",
"iwc",
"jetstream",
"kakao-bohne",
"kanaltunnel",
"kilowatt",
"kilowattstunde",
"kinetose",
"kipppunkt",
"klimafolgen",
"klimaneutralitaet",
"klimawandel",
"klimazone",
"knochenleitung",
"knoten",
"koeppen-geiger",
"kohlekraftwerk",
"kohlenstoffkreislauf",
"kompass",
"konsum",
"kontinent",
"koordinate",
"krankheits-ausbruch",
"krater",
"krill",
"kuestenschutz",
"laengengrad",
"lahar",
"lapilli",
"lastabwurf",
"lastausgleich",
"lastprofil",
"lava",
"leerfahrt",
"lenkzeit",
"lobbyismus",
"logistik",
"logistikkette",
"luftlinie",
"luftverkehr",
"maar",
"maeander",
"magma",
"magmakammer",
"mangrove",
"marge",
"marine-sanctuary",
"massstab",
"maut",
"meeresspiegel",
"megawatt",
"methan",
"migration",
"mischfonds",
"mitentscheidung",
"mobilitaet",
"mofette",
"mondfinsternis",
"mondphase",
"monokultur",
"monsun",
"mont-blanc-tunnel",
"motorbremse",
"myoglobin",
"nachhaltigkeit",
"nahversorgung",
"netzfrequenz",
"norroena-faehre",
"nutzungskonflikt",
"obsidian",
"oekosystem",
"oepnv",
"oeresundbruecke",
"opportunitaetskosten",
"panne",
"pariser-abkommen",
"pauschalreise",
"pektoralflosse",
"pellets",
"pendler",
"permafrost",
"photon",
"photovoltaik",
"phreatomagmatisch",
"plantage",
"plinianisch",
"polarkreis",
"polarnacht",
"polartag",
"ppm",
"pumpspeicher",
"pyroklastischer-strom",
"rat-der-eu",
"raumtemperatur",
"reefer-container",
"regelreserve",
"renaturierung",
"residuallast",
"retention",
"routing",
"saisonal-regional",
"schengen",
"schildvulkan",
"schlot",
"schneekettenpflicht",
"ship-strike",
"siedlungsdichte",
"solaranlage",
"sonnenfinsternis",
"sonnenwende",
"sparen",
"spedition",
"spitzenlast",
"standkosten",
"steuern",
"stratovulkan",
"strom",
"strombolisch",
"stromnetz",
"stromspeicher",
"subduktionszone",
"subtropisch-cfa",
"suffizienz",
"tachograph",
"tag-und-nacht-gleiche",
"tarif",
"temperatur",
"tephra",
"teu",
"topografie",
"topografische-karte",
"tourismus",
"treibhauseffekt",
"treibhausgas",
"tss",
"tubercles",
"turbine",
"ueberflutung",
"ueberschwemmungsgebiet",
"ueberweidung",
"ufervegetation",
"umschlag",
"umweg",
"urbanisierung",
"vei",
"verderblich",
"verdichtung",
"verkaufspreis",
"vignette",
"viskositaet",
"vogelschlag",
"vulkanasche",
"waermepumpe",
"wahrzeichen",
"walgesang",
"warndreieck",
"wartung",
"wasserkraft",
"watt",
"welt-hafen",
"welternte",
"welthandel",
"wendekreis",
"windenergie",
"windpark",
"wirkungsgrad",
"zeitzone",
"zenit",
"zersiedelung",
"zinseszins",
"zoll"
]
}
@@ -1,31 +0,0 @@
{
"generated": "2026-06-11",
"description": "Top-Level-Routes die mindestens 200 antworten müssen. Sortiert nach Funktionsgruppe.",
"public": {
"landing": ["", "index.html"],
"info": ["handbuch.html", "kontakt", "datenschutz", "impressum", "barrierefreiheit"],
"glossar": ["glossar"],
"lehrplan": ["lehrplan"],
"mindmap": ["mindmap"],
"forschung": ["forschung/", "forschung/literatur.php"]
},
"schueler_lehrer_einstieg": {
"login_login": ["login", "schueler", "teacher", "profil"]
},
"module_info": {
"active": [
"modul-klima", "modul-klima-3d", "modul-fluss", "modul-heli",
"modul-logistik", "modul-busfahrt", "modul-farmer", "modul-energiemanager",
"modul-eu-werkstatt", "modul-sonnensystem", "modul-weltkueche"
],
"planned_should_404": ["modul-fluggesellschaft", "modul-entscheidungstag"]
},
"sims_wrapper": {
"active": [
"klima-2d", "klima-3d", "fluss", "heli-game", "logistik",
"busfahrt", "farmer", "energiemanager", "eu-werkstatt",
"sonnensystem", "weltkueche", "kofferdetektiv-3d"
],
"planned": ["fluggesellschaft", "kofferdetektiv-2d", "wal"]
}
}
@@ -1,15 +0,0 @@
{
"comment": "Lokal-Test-Accounts. Auf Prod NICHT verwenden — andere IDs.",
"generated": "2026-06-11",
"klassenCode": "VRGETF",
"teacher": {
"email": "test@localhost",
"password": "test123",
"note": "Diesen Account musst du lokal in der DB anlegen, bevor die Login-Flows laufen können. Siehe README."
},
"schueler": {
"displayName": "schueler01",
"password": "test",
"klassenCode": "VRGETF"
}
}
-22
View File
@@ -1,22 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
page.on('console', msg => console.log(' [console]', msg.type(), msg.text().substring(0,150)));
page.on('pageerror', err => console.log(' [PAGEERROR]', err.message));
const res = await page.goto('http://localhost/geograsim/App/fluss?level=1');
console.log(' status:', res.status());
await page.waitForTimeout(2000);
let snap;
try {
snap = await page.evaluate(() => {
try {
const fn = window.GGS_LIVE_STATE;
if (typeof fn !== 'function') return { _type: typeof fn };
return fn();
} catch (e) { return { _error: String(e) }; }
});
} catch (e) { console.log(' EVAL ERROR:', e.message); }
console.log(' snapshot:', JSON.stringify(snap, null, 2));
await browser.close();
})();
-15
View File
@@ -1,15 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
// Mit baseURL ohne trailing slash:
const ctx1 = await browser.newContext({ baseURL: 'http://localhost/geograsim/App' });
const p1 = await ctx1.newPage();
const r1 = await p1.goto('/fluss?level=1');
console.log('no-trail /fluss:', r1.status(), p1.url());
// Mit trailing slash:
const ctx2 = await browser.newContext({ baseURL: 'http://localhost/geograsim/App/' });
const p2 = await ctx2.newPage();
const r2 = await p2.goto('fluss?level=1');
console.log('with-trail relative fluss:', r2.status(), p2.url());
await browser.close();
})();
@@ -1,294 +0,0 @@
/**
* gen-display-preview.js
* ----------------------
* Lokales Admin-Werkzeug: erstellt Bildschirmfotos aller Simulationen
* (Onboarding/Start + Spielverlauf) in zwei Auflösungen (iPad + Full HD)
* und generiert daraus eine statische Galerie-Seite.
*
* Ausgabe: App/.LocalDeveloperTools/display-preview/
* shots/<id>__<vp>__<screen>.png
* display_preview.html
*
* Start: node gen-display-preview.js
*/
const { chromium } = require('@playwright/test');
const fs = require('fs');
const path = require('path');
// --- Pfade ---------------------------------------------------------------
const APP_DIR = 'C:/xampp/htdocs/geograsim/App';
const SIMS_DIR = path.join(APP_DIR, 'sims');
const OUT_DIR = path.join(APP_DIR, '.LocalDeveloperTools', 'display-preview');
const SHOTS_DIR = path.join(OUT_DIR, 'shots');
const BASE_URL = 'http://localhost/geograsim/App/sims';
// --- Viewports -----------------------------------------------------------
const VIEWPORTS = [
{ key: 'ipad', label: 'iPad', w: 1180, h: 820 },
{ key: 'fullhd', label: 'Full HD', w: 1920, h: 1080 },
];
// --- Freundliche Namen ---------------------------------------------------
const NAMES = {
weltkueche: '🍲 Welt-Küche',
fluss: '🌊 Flussmanagement',
heli: '🚁 Helikopter-Navigation',
energiemanager: '⚡ Energiemanager',
'eu-werkstatt': '🇪🇺 EU-Werkstatt',
farmer: '🌾 Farmer',
busfahrt: '🚌 Busfahrt',
sonnensystem: '🪐 Sonnensystem',
tourismustal: '🏔️ Tourismustal',
tourismusregion: '🗺️ Tourismusregion',
logistik: '🚚 Logistik',
fluggesellschaft:'✈️ Fluggesellschaft',
staustufen: '💧 Staustufen',
entscheidungstag:'📅 Entscheidungstag',
vulkan: '🌋 Vulkan',
wal: '🐋 Wal',
kofferdetektiv: '🧳 Kofferdetektiv',
stadt: '🏙️ Stadt',
};
// --- Sims finden ---------------------------------------------------------
function findSims() {
return fs.readdirSync(SIMS_DIR, { withFileTypes: true })
.filter(d => d.isDirectory() && fs.existsSync(path.join(SIMS_DIR, d.name, 'game.html')))
.map(d => d.name)
.sort();
}
// --- In-Page: sichtbaren Start-/Weiter-Button klicken --------------------
async function clickStartLike(page) {
return await page.evaluate(() => {
const isVisible = (el) => {
if (!el) return false;
const r = el.getBoundingClientRect();
if (r.width < 4 || r.height < 4) return false;
if (r.bottom < 0 || r.right < 0) return false;
const st = getComputedStyle(el);
return st.visibility !== 'hidden' && st.display !== 'none' && st.opacity !== '0'
&& !el.disabled && !el.classList.contains('hidden');
};
// 1) Prioritäts-Selektoren (bekannte Start-/Primary-Buttons der Plattform)
const prio = [
'.ggs-qi-btn-primary', '[data-action="start"]',
'#btnStart', '#obs-start', '#phase-start',
'.sn-btn-primary', '.ggs-btn-primary',
'.era-card-cta', '.scene-btn',
'.map-btn', '.btn.primary', '.primary', '.next',
];
for (const sel of prio) {
const el = [...document.querySelectorAll(sel)].find(isVisible);
if (el) { el.click(); return sel + ' :: ' + (el.textContent || '').trim().slice(0, 24); }
}
// 2) Text-basiert — führende Emojis/Pfeile/Ziffern strippen, dann Anfang prüfen
const clean = (s) => (s || '').replace(/^[^\p{L}]+/u, '').trim();
const rx = /^(los geht|los!|los →|los\b|start|starten|jetzt starten|neue partie|partie starten|spielen|spiel starten|beginnen|anfangen|einsteigen|erntejahr starten|routenplanung starten|in dieser welt starten|szene|weiter|verstanden|fertig|karte wählen|auswählen)/i;
const cands = [...document.querySelectorAll('button, a.btn, a[role=button], .btn, [role=button], [onclick]')];
const el = cands.find(e => {
if (!isVisible(e)) return false;
const t = clean(e.textContent);
return t.length > 0 && t.length < 44 && rx.test(t);
});
if (el) { el.click(); return 'text :: ' + (el.textContent || '').trim().slice(0, 24); }
return null;
}).catch(() => null);
}
// --- Ein Screenshot ------------------------------------------------------
async function shoot(page, file) {
try {
await page.screenshot({ path: file }); // Viewport-Ausschnitt (exakte Auflösung)
return true;
} catch (e) {
console.log(' ! Screenshot-Fehler:', e.message.slice(0, 80));
return false;
}
}
(async () => {
const sims = findSims();
// Optional: nur bestimmte Sims neu schießen (HTML wird immer komplett neu erzeugt).
const onlyArg = (process.argv.find(a => a.startsWith('--only=')) || '').slice(7);
const shootList = onlyArg ? onlyArg.split(',').map(s => s.trim()).filter(Boolean) : sims;
console.log('Gefundene Sims (' + sims.length + '):', sims.join(', '));
if (onlyArg) console.log('Neu geschossen werden nur:', shootList.join(', '));
fs.mkdirSync(SHOTS_DIR, { recursive: true });
const browser = await chromium.launch();
// results[id][vp] = { start:bool, play:bool, play2:bool, errs:[] }
const results = {};
for (const vp of VIEWPORTS) {
console.log('\n===== Viewport ' + vp.label + ' (' + vp.w + '×' + vp.h + ') =====');
for (const id of shootList) {
results[id] = results[id] || {};
const r = { start: false, play: false, play2: false, errs: [] };
results[id][vp.key] = r;
const ctx = await browser.newContext({
viewport: { width: vp.w, height: vp.h },
deviceScaleFactor: 1,
});
const page = await ctx.newPage();
page.on('pageerror', e => { if (r.errs.length < 4) r.errs.push('PE:' + e.message.slice(0, 60)); });
page.on('console', m => { if (m.type() === 'error' && r.errs.length < 4) r.errs.push('CON:' + m.text().slice(0, 60)); });
const url = BASE_URL + '/' + id + '/game.html';
try {
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 30000 });
} catch (e) {
r.errs.push('GOTO:' + e.message.slice(0, 50));
}
// 1) Onboarding/Start
await page.waitForTimeout(2500);
r.start = await shoot(page, path.join(SHOTS_DIR, id + '__' + vp.key + '__start.png'));
// 2) Spielverlauf: mehrere Runden klicken (Onboarding schließen -> Menü -> Spiel -> Tutorial weg)
let clicks = 0, last = null;
for (let round = 0; round < 4; round++) {
const clicked = await clickStartLike(page);
if (!clicked) break;
clicks++;
if (clicked === last) break; // gleiches Element erneut -> Abbruch
last = clicked;
await page.waitForTimeout(800);
}
if (clicks > 0) {
await page.waitForTimeout(2500);
r.play = await shoot(page, path.join(SHOTS_DIR, id + '__' + vp.key + '__play.png'));
// 3) optionaler zweiter Play-Screen: noch ein Weiter/Start, falls vorhanden
const more = await clickStartLike(page);
if (more && more !== last) {
await page.waitForTimeout(2000);
r.play2 = await shoot(page, path.join(SHOTS_DIR, id + '__' + vp.key + '__play2.png'));
}
}
const flags = [r.start ? 'S' : '-', r.play ? 'P' : '-', r.play2 ? 'P2' : '--'].join(' ');
console.log(' ' + id.padEnd(18) + '[' + flags + ']'
+ (clicks ? ' clicks=' + clicks : ' (kein Start-Button)')
+ (r.errs.length ? ' ' + r.errs.slice(0, 2).join(' | ') : ''));
await ctx.close();
}
}
await browser.close();
// --- HTML generieren ---------------------------------------------------
const genDate = new Date().toLocaleString('de-AT', {
year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit',
});
const screens = [
{ key: 'start', label: 'Onboarding / Start' },
{ key: 'play', label: 'Spielverlauf' },
{ key: 'play2', label: 'Spielverlauf (2)' },
];
function cell(id, vp, screenKey) {
const rel = 'shots/' + id + '__' + vp.key + '__' + screenKey + '.png';
const abs = path.join(SHOTS_DIR, id + '__' + vp.key + '__' + screenKey + '.png');
if (fs.existsSync(abs)) {
return '<a href="' + rel + '" target="_blank" class="shot">'
+ '<img loading="lazy" src="' + rel + '" alt="' + id + ' ' + vp.label + ' ' + screenKey + '">'
+ '<span class="cap">' + vp.label + ' · ' + vp.w + '×' + vp.h + '</span></a>';
}
return '<div class="missing">— kein Screenshot —<span class="cap">' + vp.label + '</span></div>';
}
let blocks = '';
for (const id of sims) {
const name = NAMES[id] || (id.charAt(0).toUpperCase() + id.slice(1));
// nur Screen-Zeilen zeigen, die mindestens ein Bild haben
const activeScreens = screens.filter(sc =>
VIEWPORTS.some(vp => fs.existsSync(path.join(SHOTS_DIR, id + '__' + vp.key + '__' + sc.key + '.png')))
);
const rows = (activeScreens.length ? activeScreens : [screens[0]]).map(sc =>
'<tr><th class="screen">' + sc.label + '</th>'
+ VIEWPORTS.map(vp => '<td>' + cell(id, vp, sc.key) + '</td>').join('')
+ '</tr>'
).join('\n');
blocks += '\n<section class="sim" id="sim-' + id + '">'
+ '<h2>' + name + ' <span class="simid">' + id + '</span></h2>'
+ '<table><thead><tr><th class="screen"></th>'
+ VIEWPORTS.map(vp => '<th>' + vp.label + ' <span class="res">' + vp.w + '×' + vp.h + '</span></th>').join('')
+ '</tr></thead><tbody>' + rows + '</tbody></table></section>';
}
const nav = sims.map(id =>
'<a href="#sim-' + id + '">' + (NAMES[id] || id) + '</a>'
).join('');
const html = `<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Display-Vorschau (lokal)</title>
<style>
:root { --bg:#f4f2ec; --card:#fff; --ink:#1f2b26; --accent:#1f4b37; --muted:#6b7a72; --line:rgba(0,0,0,.08); }
* { box-sizing:border-box; }
body { margin:0; font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,sans-serif; background:var(--bg); color:var(--ink); }
header { background:var(--accent); color:#fff; padding:20px 28px; position:sticky; top:0; z-index:10; box-shadow:0 2px 10px rgba(0,0,0,.15); }
header h1 { margin:0; font-size:1.4rem; }
header .meta { font-size:.82rem; opacity:.85; margin-top:4px; }
nav.toc { display:flex; flex-wrap:wrap; gap:6px; padding:14px 28px; background:#e9e6dd; border-bottom:1px solid var(--line); }
nav.toc a { font-size:.82rem; text-decoration:none; color:var(--accent); background:#fff; border:1px solid var(--line); border-radius:999px; padding:4px 11px; }
nav.toc a:hover { background:var(--accent); color:#fff; }
main { padding:24px 28px 60px; max-width:1500px; margin:0 auto; }
section.sim { background:var(--card); border-radius:14px; padding:18px 20px 22px; margin-bottom:26px; box-shadow:0 4px 14px rgba(0,0,0,.06); scroll-margin-top:90px; }
section.sim h2 { margin:0 0 14px; font-size:1.25rem; color:var(--accent); display:flex; align-items:baseline; gap:10px; }
.simid { font-size:.72rem; font-weight:600; color:var(--muted); background:#eef0ec; padding:2px 8px; border-radius:6px; letter-spacing:.03em; }
table { width:100%; border-collapse:collapse; table-layout:fixed; }
thead th { text-align:left; font-size:.82rem; color:var(--muted); padding:0 0 8px; font-weight:700; }
thead th .res { font-weight:500; opacity:.7; }
th.screen { width:150px; vertical-align:top; font-size:.9rem; color:var(--ink); padding-top:8px; }
td { padding:6px 6px 14px; vertical-align:top; width:calc((100% - 150px)/2); }
a.shot { display:block; border:1px solid var(--line); border-radius:8px; overflow:hidden; background:#0d1512; text-decoration:none; }
a.shot img { display:block; width:100%; max-width:100%; height:auto; }
.cap { display:block; font-size:.72rem; color:var(--muted); padding:5px 8px; background:#fafafa; border-top:1px solid var(--line); }
a.shot .cap { color:#c8d4ce; background:#141f1a; border-top:none; }
.missing { display:flex; flex-direction:column; align-items:center; justify-content:center; gap:6px; min-height:120px; border:1px dashed var(--line); border-radius:8px; color:var(--muted); font-size:.85rem; background:#faf9f5; }
.missing .cap { background:none; border:none; }
@media (max-width:820px){ th.screen{width:90px;} td{width:calc((100% - 90px)/2);} }
</style>
</head>
<body>
<header>
<h1>Display-Vorschau (lokal)</h1>
<div class="meta">${sims.length} Simulationen · je Onboarding/Start + Spielverlauf · iPad 1180×820 &amp; Full HD 1920×1080 · generiert am ${genDate}</div>
</header>
<nav class="toc">${nav}</nav>
<main>${blocks}
</main>
</body>
</html>`;
const outFile = path.join(OUT_DIR, 'display_preview.html');
fs.writeFileSync(outFile, html, 'utf8');
console.log('\nHTML geschrieben: ' + outFile);
// --- Zusammenfassung ---------------------------------------------------
console.log('\n===== ZUSAMMENFASSUNG =====');
let totalShots = 0, missingPlay = [];
for (const id of sims) {
const parts = [];
for (const vp of VIEWPORTS) {
const r = (results[id] && results[id][vp.key]) || {};
const n = (r.start ? 1 : 0) + (r.play ? 1 : 0) + (r.play2 ? 1 : 0);
totalShots += n;
parts.push(vp.label + ':' + n + '/3(' + (r.start ? 'S' : '-') + (r.play ? 'P' : '-') + (r.play2 ? '2' : '-') + ')');
if (!r.play) missingPlay.push(id + '/' + vp.key);
}
console.log(' ' + id.padEnd(18) + parts.join(' '));
}
console.log('\nScreenshots gesamt: ' + totalShots);
console.log('Fehlende Play-Screens: ' + (missingPlay.length ? missingPlay.join(', ') : 'keine'));
console.log('Seite: http://localhost/geograsim/App/.LocalDeveloperTools/display-preview/display_preview.html');
})();
@@ -1,23 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1500 } });
const page = await ctx.newPage();
await page.goto('https://geograsim.at/glossar?term=reisepass');
await page.waitForTimeout(2500);
const r = await page.evaluate(() => {
const txt = document.body.innerText;
return {
hasHenley: /Henley/i.test(txt),
hasBiometric: /biometrisch/i.test(txt),
hasICAO: /ICAO/i.test(txt),
hasRelated: /Verwandt|Siehe auch|Related/i.test(txt),
hasExamples: /Beispiel/i.test(txt),
hasLinks: /Henley Passport Index|BMI|Quelle/i.test(txt),
textLength: txt.length,
};
});
console.log('reisepass-Seite:', JSON.stringify(r, null, 2));
await page.screenshot({ path: 'c:/xampp/htdocs/geograsim/.dontDeploy/playwright/glossar-reisepass.png' });
await browser.close();
})();
Binary file not shown.

Before

Width:  |  Height:  |  Size: 327 KiB

-16
View File
@@ -1,16 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
page.on('pageerror', e => console.log('PAGEERROR:', e.message));
page.on('console', m => { if (m.type()==='error') console.log('CONSOLE:', m.text().substring(0,200)); });
await page.goto('http://localhost/geograsim/App/heli-game');
await page.waitForTimeout(3000);
const info = await page.evaluate(() => ({
onb: typeof window.startHeliOnboarding,
tutorial: typeof window.GGS_TUTORIAL,
keys: window.GGS_TUTORIAL ? Object.keys(window.GGS_TUTORIAL) : null,
}));
console.log('heli:', JSON.stringify(info));
await browser.close();
})();
-20
View File
@@ -1,20 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const errors = [];
page.on('pageerror', e => errors.push('PAGEERROR: ' + e.message.substring(0,200)));
page.on('console', m => { if (m.type()==='error') errors.push('CON:'+m.text().substring(0,150)); });
const r = await page.goto('http://localhost/geograsim/App/sims/heli/game.html');
console.log('status:', r?.status());
await page.waitForTimeout(2500);
const info = await page.evaluate(() => ({
onb: typeof window.startHeliOnboarding,
tutorial: typeof window.GGS_TUTORIAL,
title: window.GGS_TUTORIAL && window.GGS_TUTORIAL.title,
simId: window.GGS_TUTORIAL && window.GGS_TUTORIAL.simId,
}));
console.log('heli direct:', JSON.stringify(info));
if (errors.length) console.log('errors:', errors.slice(0,5));
await browser.close();
})();
-16
View File
@@ -1,16 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://geograsim.at/heli-game?mission=m1');
await page.waitForTimeout(4000);
const r = await page.evaluate(() => {
const allBtns = Array.from(document.querySelectorAll('button, [role="button"]')).map(b => ({
id: b.id, cls: (b.className||'').substring(0,40), txt: (b.textContent||'').trim().substring(0,40), hidden: b.hidden
}));
const allStartLike = allBtns.filter(b => /start|freigabe|release/i.test(b.id + ' ' + b.cls + ' ' + b.txt));
return { total: allBtns.length, startLike: allStartLike.slice(0,10), first10: allBtns.slice(0,5) };
});
console.log(JSON.stringify(r, null, 2));
await browser.close();
})();
@@ -1,21 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
for (const url of [
'https://geograsim.at/heli-game',
'https://geograsim.at/heli-game?mission=m1',
'https://geograsim.at/heli-game?mission=m2',
]) {
const page = await browser.newPage();
await page.goto(url);
await page.waitForTimeout(2500);
const r = await page.evaluate(() => ({
btn: document.querySelectorAll('#startReleaseBtn').length,
title: document.title,
visible: document.querySelector('h1, h2')?.textContent?.substring(0,60),
}));
console.log(url.padEnd(55), JSON.stringify(r));
await page.close();
}
await browser.close();
})();
-13
View File
@@ -1,13 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const res = await page.goto('http://localhost/geograsim/App/heli-game');
console.log('status:', res?.status());
await page.waitForTimeout(1500);
const t = await page.title();
console.log('title:', t);
const text = await page.locator('body').innerText({ timeout: 2000 }).catch(()=>null);
console.log('text head:', (text || '').substring(0, 200));
await browser.close();
})();
-23
View File
@@ -1,23 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const errors = [];
page.on('pageerror', err => errors.push('PAGEERROR: ' + err.message));
page.on('console', msg => { if (msg.type() === 'error') errors.push('CONSOLE: ' + msg.text().substring(0,200)); });
await page.goto('http://localhost/geograsim/App/fluss?level=1');
await page.waitForTimeout(3000);
const out = await page.evaluate(() => ({
hasGGS: typeof window.__GGS__ === 'object',
hasLive: typeof window.__GGS_LIVE__ === 'object',
activeMs: window.__GGS_LIVE__ && window.__GGS_LIVE__.activeMs,
idleMs: window.__GGS_LIVE__ && window.__GGS_LIVE__.idleMs,
maxSession: window.__GGS_LIVE__ && window.__GGS_LIVE__.MAX_SESSION_MS,
idleThresh: window.__GGS_LIVE__ && window.__GGS_LIVE__.IDLE_THRESHOLD_MS,
stateScore: (window.GGS_LIVE_STATE && window.GGS_LIVE_STATE()) || null,
}));
console.log('Local Fluss after 3s:');
console.log(JSON.stringify(out, null, 2));
if (errors.length) console.log('ERRORS:', errors);
await browser.close();
})();
-19
View File
@@ -1,19 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const sims = ['fluss?level=1', 'klima-2d', 'klima-3d'];
for (const path of sims) {
const page = await browser.newPage();
await page.goto('http://localhost/geograsim/App/' + path);
await page.waitForTimeout(2500);
const info = await page.evaluate(() => ({
hasBtn: !!document.getElementById('btn-info'),
hasReg: typeof window.GGS_TUTORIAL === 'object' && typeof window.GGS_TUTORIAL.replay === 'function',
simId: window.GGS_TUTORIAL && window.GGS_TUTORIAL.simId,
title: window.GGS_TUTORIAL && window.GGS_TUTORIAL.title,
}));
console.log(path.padEnd(20), JSON.stringify(info));
await page.close();
}
await browser.close();
})();
@@ -1,19 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
const page = await ctx.newPage();
// Direkt das KD_FUNDSACHEN-Array prüfen
await page.goto('http://localhost/geograsim/App/sims/kofferdetektiv/game-3d.html');
await page.waitForTimeout(3000);
const r = await page.evaluate(() => {
if (typeof KD_FUNDSACHEN === 'undefined') return { error: 'KD_FUNDSACHEN undefined' };
return {
count: KD_FUNDSACHEN.length,
first3: KD_FUNDSACHEN.slice(0, 3).map(f => ({ name: f.name, hasGlossarSpan: /ggs-g/.test(f.info), sample: f.info.substring(0, 100) })),
glossarSpanCount: KD_FUNDSACHEN.reduce((n, f) => n + (f.info.match(/ggs-g/g) || []).length, 0),
};
});
console.log(JSON.stringify(r, null, 2));
await browser.close();
})();
-15
View File
@@ -1,15 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const ctx = await browser.newContext({ viewport: { width: 1280, height: 1200 } });
const page = await ctx.newPage();
await page.goto('https://geograsim.at/modul-kofferdetektiv');
await page.waitForTimeout(2000);
await page.evaluate(() => {
document.querySelector('.md-gallery')?.scrollIntoView({ block: 'center' });
});
await page.waitForTimeout(800);
await page.screenshot({ path: 'c:/xampp/htdocs/geograsim/.dontDeploy/playwright/kd-gallery.png' });
console.log('snapshot saved');
await browser.close();
})();
Binary file not shown.

Before

Width:  |  Height:  |  Size: 424 KiB

-26
View File
@@ -1,26 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const ctx = await browser.newContext({ viewport: { width: 1280, height: 900 } });
const page = await ctx.newPage();
const errors = [];
page.on('pageerror', e => errors.push('PAGE: ' + e.message.substring(0,150)));
page.on('console', m => { if (m.type()==='error') errors.push('CON: ' + m.text().substring(0,150)); });
const res = await page.goto('https://geograsim.at/kofferdetektiv-3d');
console.log('Status:', res?.status());
await page.waitForTimeout(4000); // 3D-Boot dauert
const info = await page.evaluate(() => ({
ggs: typeof window.__GGS__,
simId: window.__GGS__ && window.__GGS__.simId,
mode: window.__GGS__ && window.__GGS__.mode,
liveState: typeof window.GGS_LIVE_STATE,
tutorial: typeof window.GGS_TUTORIAL,
kdBase: window.KD_BASE,
threeLoaded: typeof window.THREE,
title: document.title,
visibleBody: document.body?.children?.length || 0,
}));
console.log(JSON.stringify(info, null, 2));
if (errors.length) console.log('Errors (' + errors.length + '):', errors.slice(0,5));
await browser.close();
})();
@@ -1,17 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://geograsim.at/kofferdetektiv-3d');
await page.waitForTimeout(4000);
const r = await page.evaluate(() => ({
fundsachenCount: typeof KD_FUNDSACHEN !== 'undefined' ? KD_FUNDSACHEN.length : 'undef',
glossarSpansInFundsachen: typeof KD_FUNDSACHEN !== 'undefined'
? KD_FUNDSACHEN.reduce((n, f) => n + (f.info.match(/ggs-g/g) || []).length, 0)
: 'undef',
glossarTooltipLib: typeof window.GlossarTooltip,
liveState_keys: window.GGS_LIVE_STATE ? Object.keys(window.GGS_LIVE_STATE() || {}).sort() : null,
}));
console.log(JSON.stringify(r, null, 2));
await browser.close();
})();
-17
View File
@@ -1,17 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://geograsim.at/lehrplan');
await page.waitForTimeout(2000);
// Extract Kompetenz-Slugs + Anker-Counts
const data = await page.evaluate(() => {
const out = [];
document.querySelectorAll('h2, h3, .kompetenz-title, .competence, [class*=anchor]').forEach(el => {
out.push(el.textContent.trim().substring(0, 80));
});
return { total: out.length, samples: out.slice(0,40) };
});
console.log(JSON.stringify(data, null, 2));
await browser.close();
})();
-17
View File
@@ -1,17 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const ctx = await browser.newContext();
// Try /api/lehrplan if it exists publicly
const r = await ctx.request.get('https://geograsim.at/api/lehrplan');
const txt = await r.text();
console.log('lehrplan API status:', r.status());
if (r.status() === 200) {
try {
const j = JSON.parse(txt);
const anchors = j.anchors || j.kompetenzen || j;
console.log('Sample keys:', Array.isArray(anchors) ? `array ${anchors.length}` : Object.keys(anchors).slice(0,5));
} catch { console.log('not json, head:', txt.substring(0,200)); }
}
await browser.close();
})();
@@ -1,17 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const res = await page.goto('http://localhost/geograsim/App/modul-weltkueche');
await page.waitForTimeout(700);
const r = await page.evaluate(() => {
const sec = document.getElementById('lehrplan-bezug');
const komps = [...document.querySelectorAll('.md-kompetenz .md-kompetenz-title')].map(e=>e.textContent.trim());
const anchors = document.querySelectorAll('.md-anchor').length;
const countryChips = [...document.querySelectorAll('.md-lehrplan-filters .md-chip')].map(c=>c.textContent.trim());
const empty = document.body.textContent.includes('Noch keine Kompetenzen zugeordnet');
return { hasSection: !!sec, kompetenzTitles: komps, anchorCount: anchors, countryChips, showsEmpty: empty };
});
console.log(JSON.stringify({ httpStatus: res.status(), result: r }, null, 2));
await browser.close();
})();
@@ -1,17 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const res = await page.goto('https://geograsim.at/modul-weltkueche', { waitUntil: 'networkidle' });
await page.waitForTimeout(700);
const r = await page.evaluate(() => {
const sec = document.getElementById('lehrplan-bezug');
const komps = [...document.querySelectorAll('.md-kompetenz .md-kompetenz-title')].map(e=>e.textContent.trim());
const anchors = document.querySelectorAll('.md-anchor').length;
const countryChips = [...document.querySelectorAll('.md-lehrplan-filters .md-chip')].map(c=>c.textContent.trim());
const empty = document.body.textContent.includes('Noch keine Kompetenzen zugeordnet');
return { hasSection: !!sec, kompetenzTitles: komps, anchorCount: anchors, countryChips, showsEmpty: empty };
});
console.log(JSON.stringify({ httpStatus: res.status(), result: r }, null, 2));
await browser.close();
})();
-33
View File
@@ -1,33 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const sims = [
'klima', 'fluss', 'heli', 'logistik', 'busfahrt', 'farmer',
'energiemanager', 'eu-werkstatt', 'sonnensystem', 'weltkueche',
'fluggesellschaft', 'entscheidungstag',
];
const rows = [];
for (const sim of sims) {
const page = await browser.newPage();
const r = await page.goto('https://geograsim.at/modul-' + sim);
if (r?.status() !== 200) { rows.push({sim, status:r?.status()}); await page.close(); continue; }
await page.waitForTimeout(800);
const data = await page.evaluate(() => {
const meta = document.querySelectorAll('.md-meta-item');
const out = {};
meta.forEach(el => {
const lbl = el.querySelector('.md-meta-label')?.textContent.trim().replace(':','');
const val = el.querySelector('.md-meta-value')?.textContent.trim();
if (lbl) out[lbl] = val;
});
return {
title: document.querySelector('h1')?.textContent.trim(),
meta: out,
};
});
rows.push({sim, ...data});
await page.close();
}
rows.forEach(r => console.log(JSON.stringify(r)));
await browser.close();
})();
@@ -1,37 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const errs=[]; page.on('pageerror',e=>errs.push(e.message));
await page.goto('http://localhost/geograsim/App/modul-weltkueche', { waitUntil:'domcontentloaded' });
await page.waitForTimeout(700);
async function snapshot() {
return await page.evaluate(() => {
const all = [...document.querySelectorAll('.md-anchor')];
const visible = all.filter(a => !a.classList.contains('hidden'));
const byType = t => visible.filter(a => a.dataset.anchorType===t).length;
const fachCountries = {};
visible.filter(a=>a.dataset.anchorType==='fach').forEach(a=>{ fachCountries[a.dataset.country]=(fachCountries[a.dataset.country]||0)+1; });
return { total: all.length, visible: visible.length, fachVisible: byType('fach'), fachCountries };
});
}
async function clickChip(country) {
await page.evaluate((c) => {
const btn = [...document.querySelectorAll('.md-chip')].find(b => (b.dataset.country||'')===c);
if (btn) btn.click();
}, country);
await page.waitForTimeout(200);
}
const start = await snapshot();
await clickChip(''); // Alle Länder
const alle = await snapshot();
await clickChip('DE'); // Deutschland
const de = await snapshot();
await clickChip('AT'); // Österreich
const at = await snapshot();
console.log(JSON.stringify({ start, alle, de, at, pageErrors: errs }, null, 2));
await browser.close();
})();
-15
View File
@@ -1,15 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const errs=[]; page.on('pageerror',e=>errs.push(e.message));
await page.goto('https://geograsim.at/modul-weltkueche', { waitUntil:'domcontentloaded' });
await page.waitForTimeout(900);
async function snap(){ return await page.evaluate(()=>{ const all=[...document.querySelectorAll('.md-anchor')]; const vis=all.filter(a=>!a.classList.contains('hidden')); const fc={}; vis.filter(a=>a.dataset.anchorType==='fach').forEach(a=>fc[a.dataset.country]=(fc[a.dataset.country]||0)+1); return {total:all.length, visible:vis.length, fach:vis.filter(a=>a.dataset.anchorType==='fach').length, fachCountries:fc}; }); }
async function chip(c){ await page.evaluate(c=>{const b=[...document.querySelectorAll('.md-chip')].find(x=>(x.dataset.country||'')===c); if(b)b.click();},c); await page.waitForTimeout(200); }
await chip(''); const alle=await snap();
await chip('DE'); const de=await snap();
await chip('AT'); const at=await snap();
console.log(JSON.stringify({alle,de,at,pageErrors:errs},null,2));
await browser.close();
})();
-78
View File
@@ -1,78 +0,0 @@
{
"name": "geograsim-playwright",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "geograsim-playwright",
"version": "1.0.0",
"devDependencies": {
"@playwright/test": "^1.45.0"
}
},
"node_modules/@playwright/test": {
"version": "1.60.0",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz",
"integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.60.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
}
},
"node_modules/fsevents": {
"version": "2.3.2",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
"integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/playwright": {
"version": "1.60.0",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz",
"integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.60.0"
},
"bin": {
"playwright": "cli.js"
},
"engines": {
"node": ">=18"
},
"optionalDependencies": {
"fsevents": "2.3.2"
}
},
"node_modules/playwright-core": {
"version": "1.60.0",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz",
"integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==",
"dev": true,
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"
},
"engines": {
"node": ">=18"
}
}
}
}
-17
View File
@@ -1,17 +0,0 @@
{
"name": "geograsim-playwright",
"version": "1.0.0",
"private": true,
"description": "Cross-Browser-Tests für GeoGraSim (lokal gegen XAMPP)",
"scripts": {
"test": "playwright test",
"test:smoke": "playwright test tests/stufe1-smoke/",
"test:flows": "playwright test tests/stufe2-flows/",
"test:debug": "playwright test --debug",
"test:headed": "playwright test --headed",
"report": "playwright show-report reports/html"
},
"devDependencies": {
"@playwright/test": "^1.45.0"
}
}
-25
View File
@@ -1,25 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const b = await chromium.launch(); const p = await b.newPage();
await p.addInitScript(() => {
window.__GGS__ = { simId: 'test', baseUrl: '' };
window.fetch = () => Promise.resolve({ ok:true, json:()=>Promise.resolve({}) }); // Heartbeat stummschalten
});
await p.goto('about:blank');
await p.addScriptTag({ path: 'C:/xampp/htdocs/geograsim/App/assets/js/live-client.js' });
const read = () => p.evaluate(() => window.__GGS_LIVE__ ? window.__GGS_LIVE__.activeMs : null);
const set = (v) => p.evaluate((v) => window.__GGS_LIVE__.setPaused(v), v);
await p.waitForTimeout(300);
const a1 = await read();
await p.waitForTimeout(2500); const a2 = await read(); // sollte gestiegen sein
await set(true);
await p.waitForTimeout(2500); const a3 = await read(); // sollte eingefroren sein
await set(false);
await p.waitForTimeout(2500); const a4 = await read(); // sollte wieder steigen
const grewNormal = (a2 - a1) > 1500;
const frozen = (a3 - a2) < 300;
const resumed = (a4 - a3) > 1500;
console.log(JSON.stringify({ a1,a2,a3,a4, grewNormal, frozen, resumed,
verdict: (grewNormal && frozen && resumed) ? 'PASS' : 'FAIL' }, null, 2));
await b.close();
})();
@@ -1,49 +0,0 @@
// @ts-check
const { defineConfig, devices } = require('@playwright/test');
/**
* Playwright-Konfig für GeoGraSim.
*
* Standardziel: lokaler XAMPP unter http://localhost/geograsim/App
* Über die ENV-Variable GGS_BASE_URL umstellbar (z. B. auf Prod READ-ONLY).
*
* Stand: 2026-06-11
*/
module.exports = defineConfig({
testDir: './tests',
fullyParallel: true,
forbidOnly: !!process.env.CI,
retries: process.env.CI ? 2 : 1,
// Bei Prod-Tests: max 4 Workers, damit wir nicht selbst unsere Domain
// rate-limiten. Lokal CI darf 1. Lokal manuell ohne CI: 4.
workers: process.env.CI ? 1 : 4,
reporter: [
['list'],
['html', { outputFolder: 'reports/html', open: 'never' }],
['json', { outputFile: 'reports/results.json' }],
],
use: {
baseURL: process.env.GGS_BASE_URL || 'http://localhost/geograsim/App',
trace: 'on-first-retry',
screenshot: 'only-on-failure',
video: 'retain-on-failure',
actionTimeout: 10000,
navigationTimeout: 25000,
},
projects: [
{
name: 'chromium',
use: { ...devices['Desktop Chrome'] },
},
// Bei Bedarf einkommentieren — kostet beim ersten Lauf ~200 MB Download
// {
// name: 'firefox',
// use: { ...devices['Desktop Firefox'] },
// },
// {
// name: 'webkit',
// use: { ...devices['Desktop Safari'] },
// },
],
outputDir: 'reports/artifacts',
});
@@ -1,21 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const ctx = await browser.newContext();
// 1) live-client.js enthält GGS_TUTORIAL-Doku?
const r1 = await ctx.request.get('https://geograsim.at/assets/js/live-client.js');
const js = await r1.text();
console.log('live-client.js:');
console.log(' GGS_TUTORIAL doc:', js.includes('GGS_TUTORIAL'));
console.log(' __GGS_LIVE__ :', js.includes('__GGS_LIVE__'));
console.log(' activeMs :', js.includes('activeMs'));
console.log(' MAX_SESSION_MS :', js.includes('MAX_SESSION_MS'));
// 2) teacher.html hat fluss in LIVE_PRIMARY_FIELDS + idle-tile?
const r2 = await ctx.request.get('https://geograsim.at/teacher');
const t = await r2.text();
console.log('teacher.html:');
console.log(' fluss section :', t.includes("'fluss':"));
console.log(' idle tile :', t.includes('idle') && t.includes('Zeit pausiert'));
console.log(' 5-col tiles :', t.includes('repeat(5,1fr)'));
await browser.close();
})();
-38
View File
@@ -1,38 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const sims = [
['fluss?level=1', 'fluss', 'Flussmanagement'],
['klima-2d', 'klima', 'Klimasimulation 2D'],
['klima-3d', 'klima-3d', 'Klimasimulation 3D'],
['heli-game', 'heli', 'Helikopter-Navigation'],
['weltkueche', 'weltkueche', 'Welt-Küche'],
['energiemanager', 'energiemanager', 'Energiemanager'],
['busfahrt', 'busfahrt', '🚌 Busfahrt'],
['entscheidungstag','entscheidungstag','🌅 Entscheidungstag'],
['eu-werkstatt', 'eu-werkstatt', '🏛️ EU-Werkstatt'],
['farmer', 'farmer', '🌾 Landwirtschaft'],
['fluggesellschaft','fluggesellschaft','✈️ Fluggesellschaft'],
['logistik', 'logistik', '📦 Logistik Europa'],
['sonnensystem', 'sonnensystem', '🪐 Sonnensystem'],
];
let ok=0, fail=0;
for (const [path, expSim, expTitle] of sims) {
const page = await browser.newPage();
await page.goto('https://geograsim.at/' + path);
await page.waitForTimeout(2500);
const info = await page.evaluate(() => ({
hasReg: typeof window.GGS_TUTORIAL === 'object' && typeof window.GGS_TUTORIAL.replay === 'function',
simId: window.GGS_TUTORIAL && window.GGS_TUTORIAL.simId,
title: window.GGS_TUTORIAL && window.GGS_TUTORIAL.title,
live: typeof window.__GGS_LIVE__ === 'object',
}));
const pass = info.hasReg && info.simId === expSim && info.title === expTitle && info.live;
console.log((pass?'✓':'✗'), path.padEnd(20), JSON.stringify(info));
if (pass) ok++; else fail++;
await page.close();
}
console.log('\n' + ok + '/' + (ok+fail) + ' Sims auf Prod mit GGS_TUTORIAL+__GGS_LIVE__');
await browser.close();
process.exit(fail ? 1 : 0);
})();
-17
View File
@@ -1,17 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
await page.goto('https://geograsim.at/fluss?level=1');
await page.waitForTimeout(3000);
const out = await page.evaluate(() => ({
hasLive: typeof window.__GGS_LIVE__ === 'object',
activeMs: window.__GGS_LIVE__ && window.__GGS_LIVE__.activeMs,
idleMs: window.__GGS_LIVE__ && window.__GGS_LIVE__.idleMs,
maxSession: window.__GGS_LIVE__ && window.__GGS_LIVE__.MAX_SESSION_MS,
fluss: window.GGS_LIVE_STATE && window.GGS_LIVE_STATE(),
}));
console.log('Prod Fluss after 3s:');
console.log(JSON.stringify(out, null, 2));
await browser.close();
})();
-19
View File
@@ -1,19 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const sims = ['fluss?level=1', 'klima-2d', 'klima-3d'];
for (const path of sims) {
const page = await browser.newPage();
await page.goto('https://geograsim.at/' + path);
await page.waitForTimeout(2500);
const info = await page.evaluate(() => ({
hasBtn: !!document.getElementById('btn-info'),
hasReg: typeof window.GGS_TUTORIAL === 'object' && typeof window.GGS_TUTORIAL.replay === 'function',
simId: window.GGS_TUTORIAL && window.GGS_TUTORIAL.simId,
title: window.GGS_TUTORIAL && window.GGS_TUTORIAL.title,
}));
console.log(path.padEnd(20), JSON.stringify(info));
await page.close();
}
await browser.close();
})();
-74
View File
@@ -1,74 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const out = {};
// 1) modul-weltkueche: Lehrplan-Bezug jetzt vorhanden?
{
const page = await browser.newPage();
await page.goto('https://geograsim.at/modul-weltkueche', { waitUntil: 'domcontentloaded' });
await page.waitForTimeout(1000);
out.modulWeltkueche = await page.evaluate(() => ({
kompetenzTitles: [...document.querySelectorAll('.md-kompetenz-title')].map(e=>e.textContent.trim()),
anchorCount: document.querySelectorAll('.md-anchor').length,
showsEmpty: document.body.textContent.includes('Noch keine Kompetenzen zugeordnet'),
}));
await page.close();
}
// 2) Weltküche-Sim: Artikel + Ukraine-Feedback
{
const page = await browser.newPage();
const errs=[]; page.on('pageerror',e=>errs.push(e.message));
await page.goto('https://geograsim.at/sims/weltkueche/game.html', { waitUntil:'domcontentloaded' });
await page.waitForTimeout(2000);
out.weltkueche = await page.evaluate(async () => {
try {
if (!DISHES.length) await loadWeltkuecheData();
const dish = DISHES.find(d=>d.id==='tiroler-groestl'); current={dish};
buildTaskFor('kartoffel');
return {
kartoffelArt: ING.kartoffel.art,
badArticles: Object.entries(ING).filter(([k,v])=>!['der','die','das'].includes(v&&v.art)).map(([k])=>k),
wrongUA: explainChoice('kartoffel','ukraine',false).text,
};
} catch(e){ return { error:String(e) }; }
});
out.weltkueche.pageErrors = errs;
await page.close();
}
// 3) teacher.html: lädt + neue Funktionen da (direkter Link, den das Produkt nutzt)
{
const page = await browser.newPage();
const errs=[]; page.on('pageerror',e=>errs.push(e.message));
// teacher.html leitet ohne Login auf login.html um — Navigation abfangen, sofort auswerten
await page.route('**/login.html', r=>r.abort());
await page.goto('https://geograsim.at/teacher.html', { waitUntil:'domcontentloaded' }).catch(()=>{});
await page.waitForTimeout(1500);
out.teacher = await page.evaluate(() => ({
hasRenderGesamt: typeof renderLiveGesamt === 'function',
hasQualityBar: typeof _liveQualityBar === 'function',
qualitySample: (typeof _liveQualityBar==='function') ? _liveQualityBar(8,2) : null,
tabLabels: [...document.querySelectorAll('#tab-bar .tab')].map(t=>t.textContent.trim()),
})).catch(e=>({evalError:String(e)}));
out.teacher.pageErrors = errs;
await page.close();
}
// 4) Tourismusregion passstrasse Karte
{
const page = await browser.newPage();
const mc = await page.request.get('https://geograsim.at/sims/tourismusregion/js/maps-custom.json');
const j = await mc.json();
out.tourismus = {
keys: Object.keys(j),
passBergaufPoints: j.passstrasse?.routes?.bergauf?.length ?? null,
passSlots: (j.passstrasse?.slots||[]).length,
};
await page.close();
}
console.log(JSON.stringify(out, null, 2));
await browser.close();
})();
@@ -1,33 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const errors = [];
page.on('pageerror', e => errors.push('PAGEERROR: ' + e.message.substring(0,200)));
page.on('console', m => { if (m.type()==='error') errors.push('CON:'+m.text().substring(0,150)); });
await page.goto('http://localhost/geograsim/App/sims/busfahrt/game.html');
await page.waitForTimeout(2500);
const info = await page.evaluate(() => ({
libLoaded: typeof window.GgsQuickIntro === 'object',
convReg: typeof window.GGS_TUTORIAL === 'object',
simId: window.GGS_TUTORIAL && window.GGS_TUTORIAL.simId,
title: window.GGS_TUTORIAL && window.GGS_TUTORIAL.title,
btnInDom: !!document.getElementById('btn-info'),
modalOpen: !!document.querySelector('.ggs-qi-back'),
}));
console.log('busfahrt:', JSON.stringify(info, null, 2));
// Wenn Modal offen: schließen via Klick auf Button
if (info.modalOpen) {
await page.click('.ggs-qi-btn-primary');
await page.waitForTimeout(200);
const after = await page.evaluate(() => !!document.querySelector('.ggs-qi-back'));
console.log('after close:', after);
}
// Wieder öffnen via GGS_TUTORIAL.replay
await page.evaluate(() => window.GGS_TUTORIAL.replay());
await page.waitForTimeout(200);
const reopen = await page.evaluate(() => !!document.querySelector('.ggs-qi-back'));
console.log('after replay:', reopen);
if (errors.length) console.log('errors:', errors.slice(0,5));
await browser.close();
})();
-21
View File
@@ -1,21 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const errors = [];
page.on('pageerror', e => errors.push('PE:'+e.message.substring(0,100)));
await page.goto('http://localhost/geograsim/App/sims/farmer/game.html');
await page.waitForTimeout(1500);
const info = await page.evaluate(() => ({
lib: typeof window.GgsQuickIntro === 'object',
conv: typeof window.GGS_TUTORIAL === 'object',
simId: window.GGS_TUTORIAL && window.GGS_TUTORIAL.simId,
autoOpen: !!document.querySelector('.ggs-qi-back'),
btnInfo: !!document.getElementById('btn-info'),
btnGlossar: !!document.getElementById('glossar-btn'),
openInfoFn: typeof openInfoModal,
}));
console.log('farmer:', JSON.stringify(info, null, 2));
if (errors.length) console.log('errors:', errors);
await browser.close();
})();
-34
View File
@@ -1,34 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const sims = [
'busfahrt',
'entscheidungstag',
'eu-werkstatt',
'fluggesellschaft',
'logistik',
'sonnensystem',
];
let ok = 0, fail = 0;
for (const sim of sims) {
const page = await browser.newPage();
const errors = [];
page.on('pageerror', e => errors.push('PE:'+e.message.substring(0,90)));
page.on('console', m => { if (m.type()==='error') errors.push('CON:'+m.text().substring(0,90)); });
await page.goto('http://localhost/geograsim/App/sims/' + sim + '/game.html');
await page.waitForTimeout(1500);
const info = await page.evaluate(() => ({
lib: typeof window.GgsQuickIntro === 'object',
conv: typeof window.GGS_TUTORIAL === 'object',
simId: window.GGS_TUTORIAL && window.GGS_TUTORIAL.simId,
auto: !!document.querySelector('.ggs-qi-back'),
}));
const pass = info.lib && info.conv && info.simId === sim && info.auto;
if (pass) ok++; else fail++;
console.log((pass?'✓':'✗'), sim.padEnd(18), JSON.stringify(info), errors.length ? ' errs:'+errors.slice(0,2).join(';') : '');
await page.close();
}
console.log('\n' + ok + '/' + (ok+fail) + ' GgsQuickIntro funktional');
await browser.close();
process.exit(fail ? 1 : 0);
})();
@@ -1,21 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const b = await chromium.launch(); const p = await b.newPage();
const errs=[]; p.on('pageerror',e=>errs.push(e.message)); p.on('console',m=>{if(m.type()==='error')errs.push(m.text());});
await p.route('**/login.html', r=>r.abort());
await p.goto('http://localhost/geograsim/App/teacher.html',{waitUntil:'domcontentloaded'}).catch(()=>{});
await p.waitForTimeout(1200);
const r = await p.evaluate(() => ({
hasSimWord: typeof simWord==='function',
hasSimCode: typeof simCode==='function',
logistikWord: typeof simWord==='function' ? simWord('logistik') : null,
logistikCode: typeof simCode==='function' ? simCode('logistik') : null,
unknownCode: typeof simCode==='function' ? simCode('irgendwas') : null,
logistikFields: (typeof LIVE_PRIMARY_FIELDS==='object' && LIVE_PRIMARY_FIELDS.logistik) ? LIVE_PRIMARY_FIELDS.logistik.map(f=>f.label) : null,
liveShortLogistik: typeof LIVE_SIM_SHORT==='object' ? LIVE_SIM_SHORT.logistik : null,
// Kürzel-Eindeutigkeit
codesUnique: (function(){ if(typeof SIM_LABELS!=='object') return null; var seen={},dup=[]; Object.keys(SIM_LABELS).forEach(k=>{var c=SIM_LABELS[k].c; if(seen[c])dup.push(c); seen[c]=1;}); return dup; })(),
}));
console.log(JSON.stringify({result:r, pageErrors:errs}, null, 2));
await b.close();
})();
@@ -1,26 +0,0 @@
const { chromium } = require('@playwright/test');
(async () => {
const browser = await chromium.launch();
const page = await browser.newPage();
const errors = [];
page.on('pageerror', e => errors.push('PAGEERROR: '+e.message));
page.on('console', m => { if (m.type()==='error') errors.push(m.text()); });
const res = await page.goto('http://localhost/geograsim/App/teacher');
await page.waitForTimeout(1000);
const r = await page.evaluate(() => {
const tabs = [...document.querySelectorAll('#tab-bar .tab')].map(t => t.textContent.trim());
let toggle = null;
try { toggle = (typeof _liveToggleHtml === 'function') ? _liveToggleHtml() : null; } catch(e){ toggle = 'ERR:'+e.message; }
return {
tabLabels: tabs,
hasSetLiveMode: typeof setLiveMode === 'function',
hasRenderGesamt: typeof renderLiveGesamt === 'function',
hasQualityBar: typeof _liveQualityBar === 'function',
qualitySample: (typeof _liveQualityBar === 'function') ? _liveQualityBar(8,2) : null,
toggleHasGesamt: (typeof toggle === 'string') ? toggle.includes('Gesamt') : toggle,
toggleHasTag: (typeof toggle === 'string') ? toggle.includes('Tag') : toggle,
};
});
console.log(JSON.stringify({ httpStatus: res.status(), result: r, pageErrors: errors }, null, 2));
await browser.close();
})();
@@ -1,81 +0,0 @@
// @ts-check
const { test, expect } = require('@playwright/test');
/**
* Stufe 1 · Regression: Fluss-Live-State liefert echte Werte
*
* Bug-Historie (2026-06-11): GGS_LIVE_STATE in Fluss prüfte `game.params`,
* aber `params` lebt nicht auf `game` selbst es ist nur ein berechnetes
* Result aus `E.getStatus(game)`. Daher gab GGS_LIVE_STATE() immer null
* zurück und der Lehrer-Cockpit zeigte "Diese Simulation meldet noch
* keine Live-Werte" trotz aktiver Sitzung.
*
* Fix: GGS_LIVE_STATE ruft jetzt `E.getStatus(game)` und liest `st.params`.
*
* Dieser Test ruft die Sim mit ?level=1 auf (überspringt den Level-Picker),
* wartet bis die Engine boots, und prüft dass GGS_LIVE_STATE() ein Objekt
* mit den erwarteten Schlüsseln liefert.
*/
// baseURL aus Config ist ohne trailing slash → page.goto('/fluss') würde lokal
// fälschlich auf http://localhost/fluss (404) gehen. Wir konstruieren die URL
// daher absolut. Funktioniert für Localhost mit Subpath UND Prod ohne Subpath.
const BASE = (process.env.GGS_BASE_URL || 'http://localhost/geograsim/App').replace(/\/$/, '');
test('Fluss · GGS_LIVE_STATE liefert nach Boot echte Werte', async ({ page }) => {
const errors = [];
page.on('pageerror', err => errors.push('PAGEERROR: ' + err.message));
page.on('console', msg => { if (msg.type() === 'error') errors.push('CONSOLE: ' + msg.text().substring(0, 200)); });
const res = await page.goto(BASE + '/fluss?level=1');
expect(res?.status(), 'Wrapper /fluss antwortet nicht').toBeLessThan(400);
// Auf Engine-Boot warten — Fluss setzt window.FLUSS in init() nach createGame.
await page.waitForTimeout(2500);
const info = await page.evaluate(() => ({
ggs: typeof window['__GGS__'],
engine: typeof window['FlussEngine'],
fluss: typeof window['FLUSS'],
state: typeof window['GGS_LIVE_STATE'],
}));
expect(info.ggs, `__GGS__ fehlt (errors: ${errors.join(' | ')})`).toBe('object');
expect(info.engine, `FlussEngine fehlt (errors: ${errors.join(' | ')})`).toBe('object');
expect(info.state, `GGS_LIVE_STATE fehlt (errors: ${errors.join(' | ')})`).toBe('function');
const snapshot = await page.evaluate(() => {
// @ts-ignore
const fn = window['GGS_LIVE_STATE'];
if (typeof fn !== 'function') return null;
try { return fn(); } catch (e) { return { _error: String(e) }; }
});
// 1) Snapshot muss ein Objekt sein, nicht null
expect(snapshot, 'GGS_LIVE_STATE() lieferte null (params-Bug?)').not.toBeNull();
expect(typeof snapshot, 'GGS_LIVE_STATE() lieferte kein Objekt').toBe('object');
expect(snapshot._error, 'GGS_LIVE_STATE() warf Exception: ' + snapshot?._error).toBeUndefined();
// 2) Pflichtfelder fürs Cockpit
expect(snapshot.simId).toBe('fluss');
expect(typeof snapshot.year).toBe('number');
expect(typeof snapshot.progressPct).toBe('number');
expect(typeof snapshot.budget).toBe('number');
// 3) Engine-Werte (params) — müssen Zahlen sein, nicht undefined
expect(typeof snapshot.biodiv, 'biodiv fehlt — params-Bug?').toBe('number');
expect(typeof snapshot.economy, 'economy fehlt — params-Bug?').toBe('number');
expect(typeof snapshot.flood, 'flood fehlt — params-Bug?').toBe('number');
expect(typeof snapshot.population, 'population fehlt — params-Bug?').toBe('number');
expect(typeof snapshot.food, 'food fehlt — params-Bug?').toBe('number');
// 4) Plausibilitäts-Range — params kommen aus clamp100, also 0-100 (außer population)
expect(snapshot.biodiv).toBeGreaterThanOrEqual(0);
expect(snapshot.biodiv).toBeLessThanOrEqual(100);
expect(snapshot.flood).toBeGreaterThanOrEqual(0);
expect(snapshot.flood).toBeLessThanOrEqual(100);
// 5) progressPct == 0 am Spielanfang (Jahr 0), darf aber bis 100 wachsen
expect(snapshot.progressPct).toBeGreaterThanOrEqual(0);
expect(snapshot.progressPct).toBeLessThanOrEqual(100);
});
@@ -1,31 +0,0 @@
// @ts-check
const { test, expect } = require('@playwright/test');
const slugs = require('../../fixtures/known-glossar-slugs.json');
/**
* Stufe 1 · Glossar-Slugs
*
* Prüft, dass jeder bekannte Slug
* 1) eine 200-Antwort liefert (kein 404)
* 2) das Glossar-DOM (Begriffs-Titel) tatsächlich rendert
*
* Das ist der Regressionstest gegen den Bug vom 2026-06-10
* (Tooltip-Lib + Klima-2D/3D basePath-Truthy).
*/
// Quote-Optimierung: 266 Slugs sind viel — wir laufen sie parallel.
test.describe.configure({ mode: 'parallel' });
for (const slug of slugs.slugs) {
test(`/${slug}`, async ({ page }) => {
const res = await page.goto(`/glossar?term=${encodeURIComponent(slug)}`);
expect(res.status(), `slug ${slug} antwortet nicht 200`).toBeLessThan(400);
// Glossar-Page rendert eine Tabelle oder eine Detail-Karte mit dem Begriff
const html = await page.content();
// Heuristik: der Slug sollte irgendwo im DOM auftauchen (key_slug oder Titel)
// Wir akzeptieren auch wenn der Begriff selbst (slug→Title-Heuristik) im
// Body-Text vorkommt. Echte Page-Crash würde 5xx liefern.
const bodyText = await page.locator('body').textContent({ timeout: 3000 });
expect(bodyText && bodyText.length, `leerer Body für ${slug}`).toBeGreaterThan(50);
});
}

Some files were not shown because too many files have changed in this diff Show More