1e51ef7def
- Konzept/, didaktik_geografie/, didaktik_simulation/, v2-modules/, v2-platform/ - 12 code-workspace-Files - STATUS-*.md - viele M/D/R-Änderungen an bereits getrackten Files - .gitignore verstärkt: **/.humaninput/, **/secret_keys.txt Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
735 lines
25 KiB
Markdown
735 lines
25 KiB
Markdown
# Vertrag 6: Platform Standards (Pflicht)
|
||
|
||
Was die V2-Plattform allen Modulen **liefert** und was sie von ihnen
|
||
**verlangt** — über die reine Schnittstellen-Definition hinaus. Damit
|
||
GeoGraSim als ein zusammenhängendes Produkt wirkt und nicht wie
|
||
eine Sammlung loser Apps.
|
||
|
||
Diese Standards sind nicht verhandelbar. Bei Konformitäts-Check
|
||
prüft Atlas auch die Einhaltung dieser Regeln (Bildstil-Eyeballing,
|
||
Touch-Target-Messung, Lexikon-Scan).
|
||
|
||
---
|
||
|
||
## 1. Design-Prinzipien (didaktisch)
|
||
|
||
### Wygotski-Lernarbeit, kein Spiel
|
||
GeoGraSim ist **Lernarbeit mit Simulationen**, kein Spiel. Wir
|
||
sprechen Schüler*innen als ernsthafte Bearbeiter*innen an, nicht als
|
||
Spieler*innen. Theoriebezug: Wygotski („Zone der nächsten Entwicklung").
|
||
|
||
**Verbindliches Lexikon** für alle UI-Texte:
|
||
|
||
| NICHT verwenden | STATTDESSEN |
|
||
|---|---|
|
||
| spielen, Spiel | arbeiten mit, Simulation, bearbeiten |
|
||
| Weiterspielen | Fortsetzen, weiterarbeiten |
|
||
| „Jetzt spielen" | „Simulation starten", „Los arbeiten" |
|
||
| Spielstand | Arbeitsstand, Fortschritt |
|
||
| Spieler*in | Lernende, Bearbeiter*in |
|
||
| Spielrunde | Durchgang, Arbeitsphase |
|
||
| Gameplay | Simulationsablauf, Arbeitsweise |
|
||
| „verloren", „Game Over" | „Ziel verfehlt", „Durchgang beendet" |
|
||
| Highscore | Beste Leistung, Bestwert |
|
||
| Level | OK, aber lieber „Schwierigkeit" oder „Stufe" |
|
||
|
||
**Ausnahmen**: Im Code (Variablennamen wie `gameState`, `gameTick`)
|
||
ok, da unsichtbar. Tabellennamen wie `game_levels`, `game_saves` ok.
|
||
Nur **sichtbare UI-Texte** und **Lehrer-/Schüler-Dokumentation**
|
||
folgen dem Lexikon.
|
||
|
||
### Inklusion: Easy-Sprache ist Pflicht
|
||
Jedes Modul muss alle UI-Texte in zwei Varianten anbieten:
|
||
- `<locale>-standard` — Standardsprache
|
||
- `<locale>-easy` — Leichte Sprache nach Netzwerk-Leichte-Sprache-
|
||
Regeln, A1–A2-Niveau, kurze Sätze, keine Fachbegriffe ohne
|
||
Erklärung
|
||
|
||
Easy-Variante ist **kein nettes Add-on**, sondern Pflicht für die
|
||
Inklusion (Schüler*innen mit Lese-/Lernschwächen, Deutsch-als-
|
||
Zweitsprache, kognitive Behinderung).
|
||
|
||
### Keine KI im fertigen Produkt
|
||
**Auswertungen, Bewertungen, Insight-Cards** im Lehrer-Dashboard nutzen
|
||
**parametrische Regeln**, keine KI-API-Calls.
|
||
|
||
```
|
||
✅ if classScore < 40% then showWarning("Klasse hat Schwierigkeiten")
|
||
❌ if AI.summarize(class.results) then ...
|
||
```
|
||
|
||
Begründung: Lehrpersonen müssen sich auf deterministische,
|
||
nachvollziehbare Aussagen verlassen können. Keine Halluzinationen,
|
||
keine Datenschutz-Probleme durch externe LLM-Calls.
|
||
|
||
**Erlaubt**: KI-Generierung von Assets (Bilder, Audio) **vor** dem
|
||
Deployment — siehe Punkt 5 unten.
|
||
|
||
---
|
||
|
||
## 2. iPad als Hauptreferenzgerät
|
||
|
||
GeoGraSim wird primär auf **iPad Landscape (1180 × 820 CSS-Pixel)**
|
||
genutzt — Schulen in AT/DACH setzen iPads ein.
|
||
|
||
### Layout-Breakpoints
|
||
- Desktop ≥ 1200 px: dreispaltig (Sidebar + Canvas + Sidebar)
|
||
- iPad Landscape 900–1199 px: dreispaltig (kompakter)
|
||
- iPad Portrait / Mobile < 900 px: einspaltig
|
||
|
||
### Touch-Pattern (Pflicht)
|
||
|
||
```html
|
||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
|
||
```
|
||
|
||
`viewport-fit=cover` ist **Pflicht** in jeder Modul-HTML, sonst
|
||
funktioniert `env(safe-area-inset-*)` nicht.
|
||
|
||
**CSS-Pflichten** im Modul:
|
||
```css
|
||
body {
|
||
touch-action: manipulation; /* kein Double-Tap-Zoom */
|
||
-webkit-tap-highlight-color: transparent;
|
||
}
|
||
|
||
button, .interactive {
|
||
min-width: 36px;
|
||
min-height: 36px; /* Touch-Ziel-Minimum */
|
||
}
|
||
|
||
/* Hover NUR auf Geräten mit echtem Hover */
|
||
@media (hover: hover) {
|
||
button:hover { ... }
|
||
}
|
||
|
||
/* Touch-Feedback statt Hover */
|
||
button:active { ... }
|
||
|
||
/* Form-Inputs mind. 16px font-size, sonst zoomt iOS */
|
||
input, textarea, select { font-size: 16px; }
|
||
|
||
/* Drag-Elemente brauchen touch-action: none als Kind */
|
||
.canvas-draggable { touch-action: none; }
|
||
```
|
||
|
||
### Modal-/Overlay-Pattern (Pflicht!)
|
||
|
||
**Lerngeschichte 2026-04-28**: Park-Mini-Spiel hatte am iPad einen
|
||
unerreichbaren „Schließen"-Button. Stundenlanges Warten ohne
|
||
Abbrechen. Daraus die vier Pflicht-Regeln:
|
||
|
||
1. **Höhen mit `dvh` statt `vh`**:
|
||
```css
|
||
.modal { max-height: 94dvh; }
|
||
```
|
||
|
||
2. **Safe-area-padding-bottom**:
|
||
```css
|
||
.modal { padding-bottom: max(16px, env(safe-area-inset-bottom)); }
|
||
```
|
||
|
||
3. **Aktions-Buttons sticky am unteren Modal-Rand**:
|
||
```css
|
||
.modal-actions {
|
||
position: sticky;
|
||
bottom: 0;
|
||
background: linear-gradient(to top, var(--ggs-white) 80%, transparent);
|
||
}
|
||
```
|
||
|
||
4. **Float-✕ rechts oben** als Backup:
|
||
```css
|
||
.modal-close { position: absolute; top: 8px; right: 8px; width: 36px; height: 36px; }
|
||
```
|
||
|
||
Bei kritischen Buttons (Schließen, Abbrechen, Bestätigen) Touch-Ziel
|
||
≥ 44 px.
|
||
|
||
**Globale Klassen** in `v2-platform/assets/css/design-system.css`:
|
||
`.ggs-endscreen-overlay`, `.ggs-endscreen`, `.ggs-endscreen-actions`
|
||
haben das alles zentral. Module sollen diese Klassen verwenden, nicht
|
||
eigene Modale neu bauen.
|
||
|
||
---
|
||
|
||
## 3. UI-Design-Tokens
|
||
|
||
Module nutzen **CSS-Variablen** aus `design-system.css`, keine
|
||
hardcodierten Hex-Werte.
|
||
|
||
### Farben
|
||
|
||
```css
|
||
/* Akzent (Fjord) */
|
||
--ggs-fjord: #4a7c8a;
|
||
--ggs-fjord-dark: #1f4e5a;
|
||
--ggs-fjord-light: #dae8ec;
|
||
|
||
/* Erfolg (Moss) */
|
||
--ggs-moss: #5a8a5e;
|
||
--ggs-moss-dark: #3a6b3e;
|
||
--ggs-moss-light: #dcead0;
|
||
|
||
/* Neutral (Sand) */
|
||
--ggs-sand: #e8d5b5;
|
||
--ggs-sand-dark: #c4a97a;
|
||
|
||
/* Gefahr (Coral) */
|
||
--ggs-coral: #c85c4a;
|
||
--ggs-coral-light: #f0d0ca;
|
||
|
||
/* Warnung (Orange) */
|
||
--ggs-orange: #e8833a;
|
||
|
||
/* Hintergrund */
|
||
--ggs-bg: #f5f2eb;
|
||
--ggs-bg-dark: #e8e4d8;
|
||
--ggs-white: #ffffff;
|
||
|
||
/* Text */
|
||
--ggs-text: #2a2a2a;
|
||
--ggs-text-muted: #8a8a8a;
|
||
--ggs-text-light: #b0b0b0;
|
||
|
||
/* Sonstige */
|
||
--ggs-border: #e0ddd4;
|
||
--ggs-success: #5a8a5e;
|
||
--ggs-warning: #e8833a;
|
||
--ggs-danger: #c85c4a;
|
||
--ggs-info: #4a7c8a;
|
||
```
|
||
|
||
### Spacing & Layout
|
||
|
||
| Token | Wert | Verwendung |
|
||
|---|---|---|
|
||
| `--ggs-gap-xs` | 4 px | Inline-Abstände |
|
||
| `--ggs-gap-sm` | 8 px | Form-Felder |
|
||
| `--ggs-gap-md` | 16 px | Standard |
|
||
| `--ggs-gap-lg` | 24 px | Sektionen |
|
||
| `--ggs-gap-xl` | 32 px | Hero |
|
||
| `--ggs-radius-sm` | 6 px | Pills |
|
||
| `--ggs-radius-md` | 12 px | Karten |
|
||
| `--ggs-radius-lg` | 16 px | Hero-Cards |
|
||
| `--ggs-radius-pill` | 999 px | Avatar-Kreise |
|
||
| `--ggs-shadow-sm` | `0 1px 3px rgba(0,0,0,.08)` | Karten |
|
||
| `--ggs-shadow-md` | `0 2px 8px rgba(0,0,0,.12)` | Modale |
|
||
| `--ggs-shadow-lg` | `0 4px 16px rgba(0,0,0,.16)` | Tooltips |
|
||
|
||
### Typografie
|
||
|
||
```css
|
||
--ggs-font: 'Inter', system-ui, -apple-system, sans-serif;
|
||
--ggs-font-mono: 'JetBrains Mono', 'Fira Code', monospace;
|
||
```
|
||
|
||
**Wichtig**: Modul-eigene Tokens (z.B. für besondere Stimmungen wie
|
||
Wintertag) als `--<modul>-*`-Variablen lokal definieren, aber GGS-
|
||
Tokens als Fallback referenzieren.
|
||
|
||
**Wichtig 2**: UI-Palette ≠ Bild-Palette. UI = Fjord/Moss/Sand.
|
||
Bilder = Scandinavian Flat (siehe Punkt 5).
|
||
|
||
---
|
||
|
||
## 4. Avatar-Pool
|
||
|
||
30 vorgenerierte Schüler-Avatare in 3 thematischen Gruppen.
|
||
Module dürfen den Avatar der Schüler*in aus `/api/student/me`
|
||
beziehen und für Begrüßungen / Belohnungen anzeigen.
|
||
|
||
**Pfad**: `/v2beta/assets/avatars/avatar-<slug>.png`
|
||
**Auflösung**: 1024×1024 PNG, kreisrund maskiert (`border-radius: 50%`)
|
||
|
||
### Geo-Welt
|
||
`pilotin` · `pilot` · `kartografin` · `geologe` · `meteorologin`
|
||
· `stadtplaner` · `forscherin` · `forscher` · `taucherin` · `astronaut`
|
||
|
||
### Cool & Lustig
|
||
`coole-girl` · `coole-boy` · `lustige-girl` · `lustige-boy`
|
||
· `nerd-girl` · `sportlich-boy` · `kuenstlerin` · `musiker`
|
||
· `gaertnerin` · `abenteurer`
|
||
|
||
### Tier-Begleiter
|
||
`fuchs-explorer` · `eule-prof` · `baer-foerster` · `pinguin-polar`
|
||
· `affe-tropen` · `delfin-meer` · `adler-pilot` · `schildkroete-w`
|
||
· `katze-stadt` · `biene-natur`
|
||
|
||
Bei Bedarf für neue Avatare: Plattform pflegt das, **Module
|
||
generieren keine eigenen Avatare**.
|
||
|
||
---
|
||
|
||
## 5. Bildstil — Flat Scandinavian Illustration (verbindlich)
|
||
|
||
Module-Sims stehen auf der Schülerseite nebeneinander. Ein
|
||
Stilbruch fällt sofort auf. Daher: **alle generierten Bilder**
|
||
(Splash, Cockpit-Card, Spielfeld-Hintergrund, Sprites, Marker, Glossar)
|
||
folgen demselben Stil.
|
||
|
||
### Offizieller Prompt-Block (verbatim, NICHT umformulieren)
|
||
|
||
> Flat Scandinavian illustration, wide panoramic landscape filling the
|
||
> entire 16:9 frame edge-to-edge, painted style with clean vector
|
||
> shapes, dark forest green (#1f4b37) and sage green (#4a7c4e) tones,
|
||
> yellow-mustard (#e8c547) accents, beige (#e8e4d8) buildings and
|
||
> valleys, white highlights. No text, no watermark, no logos, no
|
||
> borders, no frame.
|
||
|
||
Bei jedem Bild diesen Block voranstellen, danach nur den Szenen-Teil
|
||
ergänzen.
|
||
|
||
### Bildtypen und Auflösungen
|
||
|
||
| Bildtyp | Auflösung | Quality |
|
||
|---|---|---|
|
||
| Splash (Sim-Intro) | 1792 × 1024 (16:9) | standard |
|
||
| Cockpit-Card | ≈ 800 × 450 (16:9) | standard |
|
||
| Glossar-Bild | 1792 × 1024 | standard |
|
||
| Avatar | 1024 × 1024 | standard |
|
||
|
||
### Tabu
|
||
|
||
- Keine Schrift im Bild
|
||
- Keine Logos / Wasserzeichen
|
||
- Keine Rahmen / Borders
|
||
- Keine Stockphoto-Übernahmen — bei Bedarf neu generieren
|
||
|
||
---
|
||
|
||
## 6. Zentrale API-Keys und Plattform-Dienste
|
||
|
||
API-Keys für externe Dienste werden **zentral von der Plattform
|
||
gehalten**, nicht von einzelnen Modulen. Modul-Instanzen rufen sie
|
||
über Plattform-Proxy-Endpoints auf, damit Keys nicht in
|
||
Modul-Code/Repos landen.
|
||
|
||
| Dienst | Zweck | Plattform-Endpoint | API-Key liegt in |
|
||
|---|---|---|---|
|
||
| **DALL-E 3** | Bild-Generierung (Splash, Cards, Glossar, Sprites) | `POST /v2beta/api/asset-gen/image` | `v2-platform/.env.local` → `OPENAI_API_KEY` |
|
||
| **ElevenLabs** | Sprach-Synthese (TTS für Aufgaben, Audio-Erzähler) | `POST /v2beta/api/asset-gen/voice` | `v2-platform/.env.local` → `ELEVENLABS_API_KEY` |
|
||
| **Suno** | Hintergrundmusik | manuell durch Thomas | (Suno hat kein klassisches API) |
|
||
| **OpenStreetMap-Tile-Proxy** | Karten-Tiles (Leaflet, Maplibre) | `GET /v2beta/proxy/tile/<z>/<x>/<y>.png` | – (User-Agent gesetzt) |
|
||
| **OSRM** | Routing für Logistik-/Bus-Module | `GET /v2beta/proxy/osrm/route/...` | – (öffentlich) |
|
||
|
||
### Wichtige Regeln (entschieden 2026-05-17)
|
||
|
||
- **API-Keys liegen NUR LOKAL**, niemals auf dem Server. Schlüssel-
|
||
Diebstahl-Risiko bei kompromittiertem Server ist real, Live-Kosten
|
||
wären unkontrollierbar. Server hat keine `OPENAI_API_KEY` /
|
||
`ELEVENLABS_API_KEY` in der `.env.local`.
|
||
- **Asset-Generierung läuft VOR Deployment**, lokal durch Atlas oder
|
||
Modul-Instanz. Keine Live-Generation zur Laufzeit.
|
||
- Modul speichert generierte Assets in `<modul>/public/assets/`
|
||
und committed sie ins Repo.
|
||
- Live-Aufrufe an OpenAI/ElevenLabs **aus dem Schüler-Browser sind
|
||
verboten** (siehe „Keine KI im Produkt" in Punkt 1).
|
||
- Live-Aufrufe an Tile-Proxy / OSRM sind ok (das ist Karten-Lieferung,
|
||
keine KI).
|
||
|
||
### Plattform-Proxy-Beispiel (asset-gen, im Build-Prozess)
|
||
|
||
```bash
|
||
# Modul-Instanz ruft das Plattform-Tool auf
|
||
cd v2-modules/<slug>
|
||
php ../../v2-platform/tools/asset-gen/image.php \
|
||
--prompt "<szenen-suffix>" \
|
||
--output public/assets/splash-level1.png \
|
||
--resolution 1792x1024
|
||
```
|
||
|
||
Das Tool liest den OpenAI-Key aus `v2-platform/.env.local`, schickt
|
||
DALL-E den Prompt-Block + Suffix, speichert das Ergebnis am
|
||
gewünschten Pfad. Modul committed das PNG.
|
||
|
||
---
|
||
|
||
## 7. Multi-Locale-Strategie
|
||
|
||
GeoGraSim startet AT-only, ist aber Spec-seitig multi-locale-fähig.
|
||
|
||
### Locale-Code-Format
|
||
`<sprache>-<land>-<variante>`, z.B.:
|
||
- `de-AT-standard`, `de-AT-easy` (Pflicht heute)
|
||
- `de-DE-standard`, `de-DE-easy` (später)
|
||
- `de-CH-standard`, `de-CH-easy` (später)
|
||
|
||
### Lehrplan-Codes mit Land-Prefix
|
||
- `AT-GW-1.4.2` — Österreichischer GW-Lehrplan (Sek I)
|
||
- `DE-NRW-GEO-7-3` — NRW-Erdkunde, Klasse 7 (später)
|
||
- `CH-LP21-RZG-2.2` — Schweizer Lehrplan 21, Räume Zeiten Gesellschaften (später)
|
||
|
||
### Lokalisierte Beispiele
|
||
Geographische Beispiele in Modulen (z.B. „Wien als Beobachtungsort"
|
||
im Sonnensystem) sollen **konfigurierbar** sein:
|
||
- `country: "AT"` → Default-Beispielort Wien
|
||
- `country: "DE"` → Default-Beispielort Berlin (oder Bundesland-
|
||
Hauptstadt)
|
||
- `country: "CH"` → Default-Beispielort Zürich
|
||
|
||
Modul liest `country` aus `/api/student/me` und wählt entsprechende
|
||
Beispiele. Wenn das Modul keine geografischen Beispiele hat
|
||
(z.B. Logistik mit ganz Europa), spielt das keine Rolle.
|
||
|
||
### Was heute zu tun ist
|
||
- **Sprache**: alle Texte in i18n-Files mit `de-AT-standard` und
|
||
`de-AT-easy`
|
||
- **Lehrplan**: alle Codes mit `AT-`-Prefix
|
||
- **Beispiele**: AT-zentriert, aber nicht „nur AT funktioniert"
|
||
hardcoden (z.B. nicht nur österreichische Stadtnamen erlauben)
|
||
|
||
### Was kommt wenn DE/CH dazu sollen
|
||
- **Inhaltsarbeit** (Übersetzungen, neue Lehrplan-Anker einpflegen) —
|
||
nicht Code-Refactor
|
||
- Neue i18n-Files anlegen
|
||
- Neue Beispielort-Mappings
|
||
- Neue `country`-Werte in der Plattform freischalten
|
||
|
||
---
|
||
|
||
## 9. Barrierefreiheit (Pflicht — Stufe 1 WCAG 2.1 AA)
|
||
|
||
A11y ist **kein Add-on**, sondern Pflicht für jedes V2-Modul ab Tag 1.
|
||
Begründung: EU Web Accessibility Directive verlangt für öffentlich
|
||
finanzierte Bildung WCAG 2.1 AA. Außerdem ist nachgereicht-A11y bei
|
||
12+ Modulen ein Refactor-Albtraum — heute eingebaut kostet ~5%
|
||
Mehraufwand pro Modul, später nachgerüstet ein Vielfaches.
|
||
|
||
### 9.1 Kontraste (WCAG 2.1 AA)
|
||
|
||
- **Body-Text auf Hintergrund**: mind. 4.5:1
|
||
- **Großer Text (≥ 18px) auf Hintergrund**: mind. 3:1
|
||
- **UI-Komponenten (Buttons, Form-Elemente, Icons)**: mind. 3:1
|
||
gegen umgebenden Hintergrund
|
||
- **Focus-Indikatoren**: mind. 3:1 gegen unfokussierten Zustand
|
||
|
||
Standard-Tokens müssen das erfüllen — Atlas prüft `--ggs-text` auf
|
||
`--ggs-bg` mit axe-core o.ä. im Konformitäts-Check.
|
||
|
||
### 9.2 High-Contrast-Mode — zwei Varianten (Tri-State)
|
||
|
||
Plattform liefert **zwei** Token-Sets für High-Contrast:
|
||
|
||
- **hell** (`data-high-contrast="light"`) — schwarz auf weiß, dunkel-
|
||
saturierte Farben (#001a4d, #003300, #800000). Default für
|
||
`preferences.highContrast === true`, weil visuell ruhiger und für
|
||
die meisten Schüler*innen mit Sehschwäche besser.
|
||
- **dunkel** (`data-high-contrast="dark"`) — gelb/grün auf schwarz.
|
||
Für Schüler*innen die ein dunkles Schema explizit bevorzugen.
|
||
|
||
```css
|
||
body[data-high-contrast="light"] {
|
||
--ggs-bg: #ffffff; --ggs-white: #ffffff;
|
||
--ggs-text: #000000; --ggs-text-muted: #000000;
|
||
--ggs-fjord: #003366; --ggs-fjord-dark: #001a4d;
|
||
--ggs-moss: #1a4d1a; --ggs-coral: #800000;
|
||
--ggs-border: #000000;
|
||
}
|
||
body[data-high-contrast="dark"] {
|
||
--ggs-bg: #000000; --ggs-white: #000000;
|
||
--ggs-text: #ffffff; --ggs-fjord: #ffff00;
|
||
--ggs-moss: #00ff00; --ggs-coral: #ff6060;
|
||
--ggs-border: #ffffff;
|
||
}
|
||
```
|
||
|
||
Aktiviert via `preferences.highContrast` aus `/api/student/me`. Bei
|
||
`true` setzt das Modul den Default `data-high-contrast="light"` und
|
||
bietet im Topbar einen **Tri-State-Toggle** an: aus → hell → dunkel →
|
||
aus. Schüler*in kann zwischen den beiden HC-Varianten wechseln.
|
||
|
||
### 9.3 Reduced Motion (Pflicht)
|
||
|
||
```css
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*, *::before, *::after {
|
||
animation-duration: 0.01ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
transition-duration: 0.01ms !important;
|
||
scroll-behavior: auto !important;
|
||
}
|
||
}
|
||
```
|
||
|
||
Plus: **alle Auto-Play-Animationen** (Sonnensystem-Drohnenflug,
|
||
Klima-Zeitraffer, Logistik-Tag-Ablauf) brauchen einen sichtbaren
|
||
Stop/Pause-Button. Bei `preferences.reducedMotion === true` aus dem
|
||
Profil: keine Auto-Play, manueller Start nötig.
|
||
|
||
### 9.4 Epilepsie-Trigger vermeiden
|
||
|
||
- Keine Blitze > 3 Hz (3 Wechsel pro Sekunde)
|
||
- Keine Vollbild-Farbänderungen (Rot-Schwarz-Wechsel etc.)
|
||
- Keine Stroboskop-Effekte
|
||
- Bei Explosions-/Crash-Animationen (Heli, Logistik): max. 1 Sekunde
|
||
intensives Effekt-Frame, dann Beruhigung
|
||
|
||
### 9.5 Keyboard-Navigation
|
||
|
||
Jedes interaktive Element ist per Tastatur erreichbar:
|
||
|
||
- **Tab/Shift+Tab**: Fokus-Wechsel in logischer Reihenfolge
|
||
- **Enter / Space**: aktiviert Buttons und Links
|
||
- **Esc**: schließt Modale und Overlays
|
||
- **Pfeiltasten**: navigieren in Listen, Tabs, Slider
|
||
- **Home/End**: erste/letzte Position in Listen
|
||
|
||
Kein `tabindex` > 0 (zerstört natürliche Reihenfolge). `tabindex="0"`
|
||
für Custom-Widgets erlaubt, `tabindex="-1"` für programmatischen
|
||
Fokus.
|
||
|
||
### 9.6 Focus-Indikatoren
|
||
|
||
```css
|
||
:focus-visible {
|
||
outline: 3px solid var(--ggs-fjord-dark);
|
||
outline-offset: 2px;
|
||
}
|
||
|
||
/* High-Contrast-Variante */
|
||
body[data-high-contrast="true"] :focus-visible {
|
||
outline: 3px solid #ffff00;
|
||
outline-offset: 2px;
|
||
}
|
||
```
|
||
|
||
**Niemals** `outline: none` ohne sichtbaren Ersatz.
|
||
|
||
### 9.7 Information nicht nur durch Farbe
|
||
|
||
❌ Nur grüne Markierung für „richtig", nur rote für „falsch"
|
||
✅ Grün **plus** Häkchen-Icon, Rot **plus** Kreuz-Icon
|
||
|
||
Gilt auch für Charts, Karten-Marker, Status-Pills. Daltonismus (8% der
|
||
männlichen Bevölkerung) verlangt das.
|
||
|
||
### 9.8 ARIA-Pattern (Mindeststandard)
|
||
|
||
- **Buttons**: `<button>` (nicht `<div onclick>`), bei Icon-only zusätzlich `aria-label`
|
||
- **Modale**: `<dialog>` oder `role="dialog" aria-modal="true"` mit `aria-labelledby`
|
||
- **Toggles**: `aria-pressed="true|false"`
|
||
- **Live-Updates** (Score, Telemetry-relevante Hinweise): `<div aria-live="polite">`, kritische Warnungen `aria-live="assertive"`
|
||
- **Form-Felder**: `<label for="...">` Pflicht, kein Floating-Label-only
|
||
- **Bilder**:
|
||
- inhaltlich: `alt="<Beschreibung>"`
|
||
- dekorativ: `alt=""` (nicht weglassen!)
|
||
- komplexe Diagramme: `alt="<Kurzbeschreibung>"` plus `aria-describedby` auf Lang-Beschreibung
|
||
|
||
### 9.9 Skalierbarer Text
|
||
|
||
- Body-Text in `rem` (basiert auf User-Browser-Zoom)
|
||
- Layout muss bei **200% Browser-Zoom** noch funktionieren (kein
|
||
horizontales Scrolling, keine abgeschnittenen Buttons)
|
||
- Touch-Ziele schon ≥ 36 px (haben wir), bei kritischen Buttons ≥ 44 px
|
||
- Min-Schriftgröße im Body: `0.95rem` (≈ 15.2 px)
|
||
|
||
### 9.10 Profil-Settings (über `/api/student/me`)
|
||
|
||
```json
|
||
"preferences": {
|
||
"soundOn": true,
|
||
"musicOn": false,
|
||
"highContrast": false,
|
||
"reducedMotion": false,
|
||
"screenReader": false,
|
||
"textScale": "normal" // "normal" | "large" | "xlarge"
|
||
}
|
||
```
|
||
|
||
`screenReader: true` bedeutet: Schüler*in nutzt Screen-Reader. Modul
|
||
soll dann visuelle Verzweigungen (z.B. „klicke auf das gelbe Land")
|
||
durch alternative Formulierungen ersetzen oder einen Hinweis an die
|
||
Lehrperson via Telemetry schicken (siehe unten).
|
||
|
||
### 9.11 Telemetry-Erweiterung für A11y
|
||
|
||
Wenn ein Modul für eine konkrete Schüler*in Barrieren erkennt, die
|
||
nicht überwindbar sind (z.B. Modul ist visuell-zwingend, Schüler*in
|
||
nutzt Screen-Reader), soll es ein neues Telemetry-Event emittieren:
|
||
|
||
```json
|
||
{
|
||
"type": "accessibility-blocker",
|
||
"moduleSlug": "...",
|
||
"blockerType": "visual-required" | "audio-required" | "mouse-required",
|
||
"hint": "Karten-Tap nicht per Tastatur ersetzbar in dieser Version",
|
||
"ts": "..."
|
||
}
|
||
```
|
||
|
||
Lehrer-Cockpit zeigt das prominent — Lehrperson kann der Schüler*in
|
||
ein anderes Modul oder eine offline-Alternative geben.
|
||
|
||
### 9.12 Roadmap (Stufe 2 + 3 — nicht heute Pflicht)
|
||
|
||
Modul-Instanzen sollen heute schon stufe-2-kompatibel bauen:
|
||
|
||
- **Stufe 2** (V2 stable, Modul für Modul nachziehen):
|
||
- Vollständige Screen-Reader-Verträglichkeit (NVDA, VoiceOver getestet)
|
||
- Live-Regions für Score-Updates und Phase-Wechsel
|
||
- Lehrer-A11y-Cockpit (sieht pro Schüler*in welche A11y-Settings aktiv sind, kann Modul-Vorschläge filtern auf „barrierefreie" Module)
|
||
- AAA-Kontrast-Mode (7:1)
|
||
- Erweiterte Schrift-Skalierung
|
||
- Sprachausgabe-Toggle pro Modul (TTS für alle Aufgaben-Texte)
|
||
|
||
- **Stufe 3** (Forschungs-Track, später):
|
||
- Audio-First-Varianten ausgewählter Module für blinde Schüler*innen
|
||
(binaurales Audio, sonifizierte Karten/Diagramme)
|
||
- Gebärdensprach-Videos für gehörlose Schüler*innen
|
||
- Eigene Module für besondere Bedürfnisse
|
||
|
||
Recherche-Snapshot zu Stufe 3 liegt in
|
||
`memory/project_a11y_audio_first_research.md` (für spätere
|
||
Verwendung — kein heutiger Implementierungs-Auftrag).
|
||
|
||
### 9.13 Konformitäts-Check (Stufe 1)
|
||
|
||
Atlas prüft beim Lieferungs-Empfang automatisiert:
|
||
|
||
1. ✅ **axe-core-Scan** auf gerendertem Modul-DOM (keine Critical/Serious-Issues)
|
||
2. ✅ **Kontrast-Audit** aller Text/Hintergrund-Kombinationen ≥ 4.5:1
|
||
3. ✅ **Keyboard-Navigation-Test**: Tab-Reihenfolge erreicht alle interaktiven Elemente
|
||
4. ✅ **Focus-Indikator vorhanden** (kein `outline: none` ohne Ersatz)
|
||
5. ✅ **`prefers-reduced-motion` respektiert** (Headless-Browser-Test mit gesetztem Flag)
|
||
6. ✅ **High-Contrast-Mode-Test**: Modul mit `body[data-high-contrast="true"]` rendert noch alle Texte sichtbar
|
||
7. ✅ **Alt-Texte vorhanden** auf allen `<img>` (auch leere für dekorative)
|
||
8. ✅ **Semantische Buttons**: keine `<div onclick>` für interaktive Aktionen
|
||
|
||
Bei Verstoß: Lieferung wird abgewiesen. A11y ist nicht verhandelbar.
|
||
|
||
---
|
||
|
||
## 11. Gemeinsame Ressourcen — Shared-Asset-Pool
|
||
|
||
Damit nicht jedes Modul, das Wien zeigt, sein eigenes Wien-Bild
|
||
generiert: Atlas pflegt einen zentralen Pool unter
|
||
`v2-platform/assets/shared/`, alle Module verlinken via URL.
|
||
|
||
### Pool-Kategorien
|
||
|
||
```
|
||
v2-platform/assets/shared/
|
||
├── cities/ ← Stadt-Bilder im GeoGraSim-Bildstil (1792×1024 PNG)
|
||
├── icons/ ← UI-Icons (SVG vorzugsweise)
|
||
├── glossar/ ← Glossar-Bilder (160 aus V1, Migration Welle 1)
|
||
├── bg-music/ ← Suno-Hintergrundmusik
|
||
└── ui-sounds/ ← UI-Feedback-Töne (Phase 2)
|
||
```
|
||
|
||
Pro Unterordner ein `PROVENIENZ.md`-File mit Inventar (welches Asset
|
||
wann von wo, Lizenz, welche Module nutzen es).
|
||
|
||
### Modul-Nutzung
|
||
|
||
Manifest deklariert `sharedAssets` als Map:
|
||
```json
|
||
"sharedAssets": {
|
||
"cities": ["wien", "innsbruck"],
|
||
"bg-music": ["fjord-calm"]
|
||
}
|
||
```
|
||
|
||
URL-Schema im Modul-Code: `/v2beta/assets/shared/<kategorie>/<slug>.<ext>`.
|
||
|
||
### Workflow „Asset noch nicht im Pool"
|
||
|
||
1. Modul-Instanz pingt Atlas in `_inbox/zentrale/`:
|
||
*„Brauche 'linz' im Cities-Pool. Verwendung: Logistik-V2-Auftrag."*
|
||
2. Atlas generiert lokal mit DALL-E (`tools/asset-gen/image.php …`),
|
||
committet ins Pool
|
||
3. Atlas antwortet mit URL + Inventar-Eintrag in `PROVENIENZ.md`
|
||
4. Modul-Instanz ergänzt `sharedAssets`-Manifest
|
||
|
||
### `.humanInput/` als Rohstoff-Quelle
|
||
|
||
Thomas pflegt `.humanInput/` als persönliches Werkstatt-Lager
|
||
(Audio-Files, Sprites, Pflichtenhefte, Prototyp-HTMLs). Das ist
|
||
**nicht** Teil des Repository-Deployment, sondern Vorrats-Sammlung.
|
||
|
||
Wenn ein Asset von dort in V2 wandert:
|
||
- **Modul-spezifisch** → kopiert nach `v2-modules/<slug>/public/assets/`
|
||
- **Geteilt** → kopiert nach `v2-platform/assets/shared/<kategorie>/`
|
||
- Provenienz in Modul-`docs/ASSET-PROVENIENZ.md` oder Pool-Inventar
|
||
|
||
`.humanInput/` selbst bleibt unverändert — auch wenn ein Asset schon
|
||
verbaut ist, bleibt das Original liegen als Backup.
|
||
|
||
### Konformitäts-Check
|
||
|
||
Atlas prüft beim Lieferung-Empfang: alle in `sharedAssets` deklarierten
|
||
Assets müssen im Pool existieren. Wenn nicht: Lieferung wird
|
||
abgewiesen mit konkretem Hinweis, was Modul-Instanz bei Atlas
|
||
bestellen muss.
|
||
|
||
### Was NICHT in den Shared-Pool gehört
|
||
|
||
- **Modul-spezifische Assets** (Modul-Logo, modul-eigene Sprites) →
|
||
`v2-modules/<slug>/public/assets/`
|
||
- **Avatare** → eigene Top-Level-Sektion `v2-platform/assets/avatars/`
|
||
(kein `shared/`, weil schon etabliert)
|
||
- **Schüler-Uploads** → `v2-platform/uploads/<slug>/student-<id>/`
|
||
|
||
---
|
||
|
||
## 10. Sprachregeln im Detail
|
||
|
||
### Lehrer-Anrede
|
||
- Du-Form für Lehrpersonen (modern, partnerschaftlich)
|
||
- „Lehrperson" / „Lehrperson" geschlechtsneutral, NICHT „Lehrer"
|
||
als Default
|
||
|
||
### Schüler-Anrede
|
||
- Du-Form für Schüler*innen
|
||
- „Schüler*in" mit Doppelpunkt-Form geschlechtsinklusiv
|
||
- Im Easy-Sprache-Modus: Du-Form, kurze Sätze, „Schüler" oder
|
||
„Kind" je nach Kontext (Doppelpunkt-Form ist für Easy-Sprache
|
||
schwer lesbar — Atlas-Empfehlung: in Easy „du" oder direkter
|
||
Plural „die Kinder")
|
||
|
||
### Tonalität
|
||
- Freundlich, aber nicht infantil
|
||
- Fehler nicht als „falsch" → „Probiere es nochmal" / „Schau dir
|
||
das nochmal an"
|
||
- Erfolg nicht als „toll, gewonnen" → „Geschafft" / „Ziel erreicht"
|
||
|
||
---
|
||
|
||
## Konformitäts-Check für diese Standards
|
||
|
||
Atlas prüft beim Konformitäts-Check (siehe [delivery-format.md](delivery-format.md)):
|
||
|
||
1. ✅ `viewport-fit=cover` im `<meta viewport>`
|
||
2. ✅ Alle Touch-Targets ≥ 36 px (auto-Scan)
|
||
3. ✅ Modale nutzen `dvh` und `safe-area-inset-bottom`
|
||
4. ✅ Keine hardcodierten Hex-Werte (nur `var(--ggs-*)` oder
|
||
`var(--<modul>-*)`)
|
||
5. ✅ Lexikon-Scan in i18n-Files: keine Spielsprache (siehe Punkt 1)
|
||
6. ✅ Keine `fetch('https://api.openai.com/...')` o.ä. im Modul-Code
|
||
(außer expliziter Plattform-Proxy)
|
||
7. ✅ Bildstil-Eyeballing (manueller Check durch Atlas: passen die
|
||
Bilder zum Flat-Scandinavian-Look)
|
||
8. ✅ Easy-Sprache-i18n vollständig (kein Schlüssel fehlt)
|
||
|
||
---
|
||
|
||
## ✅ Geklärt mit Thomas (2026-05-17)
|
||
|
||
- **Hex-Werte strikt blockieren**: ja, im Konformitäts-Check verboten.
|
||
Modul-eigene Spezialfarben als `--<modul>-*`-CSS-Variablen lokal,
|
||
Atlas pflegt Whitelist pro Modul. Hex direkt im Code → Lieferung
|
||
abgewiesen.
|
||
- **Zentrale Sound-Library**: Phase-2-TODO. Heute: Module nutzen
|
||
eigene Sounds, Atlas dokumentiert. In Phase 2 entsteht
|
||
`v2-platform/assets/sounds/`-Library mit UI-Standardtönen.
|
||
- **Multi-Locale Country-Erkennung**: nicht aus IP/Domain raten —
|
||
zu fehleranfällig. `country` bleibt Profil-Setting (von Lehrperson
|
||
beim Anlegen der Klasse, vererbt auf Schüler*innen, im Schüler-
|
||
Profil änderbar).
|
||
- **Suno-Musik**: bleibt manuell durch Thomas (Suno hat keine saubere
|
||
API, Musik-Wahl ist kreative Entscheidung).
|
||
- **ElevenLabs-Stimmen-Pool**: Atlas pflegt 3–5 deutsche Stimmen
|
||
(„Erzählerin warm", „Erzähler sachlich", „Kind freundlich") in
|
||
Plattform-Konfig. Module geben Pool-ID an, kein eigenes Stimmen-
|
||
Picking. Konsistenz + Wahlfreiheit.
|