- Logistik: Musik-Player Playlist-Modus (5 Gruppen, 20 Tracks) - Heli: End-Screen auf .ggs-endscreen, Mission-Bilder, Voice-Lines, Briefing-Audio - Logistik: Layout-Tausch Auftraege+Fahrzeuge links, Karte rechts - Logistik: Tier-1-Staedte ausgebaut, Auto-Timescale-Badge - Logistik: Roadnet/Railnet Dijkstra-Routing, Balance-Updates - Atlas: 5 Atlas-Inbox-Nachrichten (Cards-Pattern, DALL-E-Key, Musik-Playlists) - Status-Updates Heli + Logistik Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
78 KiB
instanz, rolle, stand_seit, phase
| instanz | rolle | stand_seit | phase |
|---|---|---|---|
| logistik | Simulation „Logistik Europa" (Modul 11) | 2026-04-19 | Phase 8d — Integrations-Vertrag §6 umgesetzt (mode-check + assessment-calls) + L1-UI-Polish + Manueller Fahrzeugkauf ab L2. Wartet auf Atlas-Reviews (3 offene Mails) |
Status — Logistik-Instanz
Rolle und Scope
- Eigner:
App/sims/logistik/(Gerüst kommt von Atlas) - Eigner:
App/pages/logistik.php,App/pages/modul-logistik.php - Eigner:
App/php/api/logistik-*.php - Optional: neue MySQL-Tabellen
lg_…(nur nach Atlas-Abstimmung) - Plattform-Zentrale ist Atlas — Anfragen über
_inbox/zentrale/
Aktueller Stand
- 2026-04-19 23:15 — Kickoff-Briefing von Atlas erhalten
- 2026-04-19 23:25 — Briefing + Pflichtenheft (alle Schlüsselkapitel) gelesen
- 2026-04-19 23:30 — Empfangsbestätigung an Zentrale geschickt
- 2026-04-20 00:10 — Atlas-Antworten auf alle 4 Rückfragen erhalten
- 2026-04-20 00:20 — Quittung an Atlas (Routing bestätigt, alle Punkte übernommen)
- Warte auf: Atlas baut Gerüst (module_info, Landing-Card, Detailseite, Wrapper, Skelette unter
App/sims/logistik/)
Geklärte Entscheidungen (Atlas-Antwort 00:10)
- Lehrplan:
kompetenzen.jsonals Vorab-Skizze (status: "proposed") nach Gerüst, final nach Phase 2 - Glossar: Atlas koordiniert Anfrage; ~10 von 13 Begriffen neu, reicht bis Phase 6
- Landing: Eigene Gruppe „Wirtschaft & Verkehr" (LOCKED bis FREE)
- Tile-Server: Carto Positron
https://{s}.basemaps.cartocdn.com/light_all/{z}/{x}/{y}{r}.png, Leaflet 1.9.4,minZoom: 4, maxZoom: 10 - Routing: bestätigt — L1 Luftlinie×1.3, L2/L3 hand-gepflegte Polylines in
lg-routes-osm.json, OSRM erst auf Thomas-Wunsch - State-Machine: Atlas legt Enum exakt nach Pflichtenheft Kap 44.2 ins
engine.js-Skelett
Phasenplan (aus Briefing)
- Phase 0 — Balance-Matrix + Test-Harness + Headless-Runner-Skelett → Atlas-Review
- Phase 1 — Fundament (engine.js + Karte + Seed-Daten)
- Phase 2 — Kern-Loop (Level 1 spielbar)
- Phase 3 — Kostenmodell + Mehrfahrzeuge + mehrere Aufträge (Level 2)
- Phase 4 — Bahn + Häfen + Intermodal (Level 3)
- Phase 5 — Hilfestufen + Events
- Phase 6 — Minigames + Sprachregel-Check + Leichte Sprache
- Phase 7 — Lehrkraftmodus + Analytics + Polish
Offene Aufgaben (kurzfristig)
App/docs/module-interface.mdAbschnitte 4a/4b/4c/7b lesen- Sobald Gerüst von Atlas steht:
balance-matrix.mdschreiben (Werte aus Kap 65 + Schätzwerte) test.htmlmit 7 Pflichttests anlegen- Headless-Runner-Skelett
runLevel(levelId, seed, strategy)definieren - Atlas-Review von Phase 0 anfordern, bevor Phase 1 startet
Blocker
- Keine. Wartepunkt: Atlas-Gerüst (≈ 2 Sessions geschätzt)
Konventions-Anker (Erinnerung)
- Sprachregel 4a: keine „spielen / Spiel / Spieler"
- Leichte Sprache 4b:
pickText()-Pattern für alle UI-Texte - iPad 4c: 1180×820 Landscape, 36 px Touch-Ziele, kein Hover-Kleber
- Autosave 7b: Pflicht bei state-relevanten Übergängen
- Keine KI im Produkt: Auftragstexte/Events/Hilfe vorab generieren, statisch ausliefern
- Inbox-Check vor jeder „Fertig"-Meldung
- Commits:
Logistik: <Kurzbeschreibung>
Komplexitätshinweis
Atlas schätzt 30–50 Sessions für das Gesamtmodul. Phasenschnitte sauber halten, nicht den ganzen Brocken auf einmal angehen.
Tagesabschluss 2026-04-20 (00:20)
- Kickoff + Pflichtenheft gelesen
- Empfangsbestätigung + 4 Rückfragen an Atlas verschickt
- Atlas-Antworten gelesen, alle Entscheidungen quittiert
- Routing-Strategie (L1 Luftlinie×1.3 / L2-L3 Hand-Polylines / kein OSRM) bestätigt
- Nächstes (sobald Gerüst steht):
balance-matrix.md→ 7 Pflichttests intest.html→ Headless-Runner-SkelettrunLevel(levelId, seed, strategy) - Blocker: keiner — wartet auf Atlas-Gerüst (~2 Sessions)
- Offen für Thomas: keine akute Frage, alles geklärt
Tagesabschluss 2026-04-20 (00:55)
- Atlas-Gerüst empfangen (DB, Landing-Card, PHP-Wrapper, Sim-Skelette, Seeds)
- 7 Pflichttests in
test.htmlstatisch geprüft + via Python-Mathematik verifiziert → 22 von 22 Test-Cases bestehen rechnerisch, Browser-Bestätigung steht aus - Phase 0 v0.1 geliefert:
App/sims/logistik/balance-matrix.mdv0.1App/sims/logistik/headless-runner.html(Skelett, alles SKIP)
- Atlas-Review angefordert
Tagesabschluss 2026-04-20 (01:30) — Phase 0 v0.2 nach Atlas-Klarstellung
Atlas hat klargestellt: Phase 0 ist meine Arbeit, das Gerüst war nur Vorarbeit. Konkrete Atlas-Forderungen alle abgehakt:
- balance-matrix.md v0.2 — Rationale-Spalte je Parameter,
INSERT-SQLs für
game_levels, Konsistenz-Checks an Atlas, Event-Wahrsch. als Multiplikator umstrukturiert,noopzur Strategieliste - headless-runner.js (NEU, vorher .html) — Vanilla-JS-Modul,
Browser+Node-kompatibel via UMD, Mulberry32-RNG, runLevel-Vertrag,
4 Strategien (
nooplauffähig +naive/greedy/optimalals Stubs) - headless-runner.html umgebaut zu dünner UI-Hülle (Logik in .js)
- test.html erweitert um:
- Test 8 — Edge-Cases (8 Cases: leere Polyline, getrennter Dijkstra-Graph, Pfad zum Selbst, negative Hours, null-Werte, unbekannter Modus)
- Test 9 — Seeded-Random (4 Cases: Determinismus, verschiedene Seeds, Range, Seed 0)
- Test 10 — Runner-Vertrag (10 Cases: noop läuft, reproduzierbar, Stubs werfen kontrolliert)
group()und Render auf async umgebaut, damit Test 10 (await runLevel) sauber läuft
- Python-Verifikation der Mathematik: alle neuen Cases grün (10 von 10)
- Atlas-Review erneut angefordert mit aktualisierten Artefakten
Nächstes (nach Review-OK): Phase 1 — engine.js tick() Loop +
Leaflet-Karte mit 13 Seed-Locations
Blocker: Atlas-Review + Thomas-Browser-Test (test.html + headless-runner.html)
Offen für Thomas: einmal beide HTML-Seiten öffnen, Status melden
Tagesabschluss 2026-04-20 (02:30) — Phase 1 ausgeliefert
Phase 0 von Atlas mit BESTANDEN reviewt (01:45). Doku-Korrekturen aus
Review umgesetzt (Bahnnetz-Distanzen Paris↔Rotterdam=520, Paris↔München=820;
INSERT-Schema mit scenario+levelNameEasy in params); 3 Logistik-Level
sind in DB. Phase 1 komplett implementiert:
-
engine.js erweitert:
loadContent(game, seeds)— INIT → LOADING_CONTENT → READYstartPlanning(game)— READY → PLANNINGstartSimulation(game)— PLANNING → RUNNING (paused=false)pause(game)/resume(game)— User-Pause via paused-FlagsetTimeScale(game, scale)— 1×/2×/4×/8×onStateChange(game, callback)→ unregister-Funktion (für Autosave 7b)tick(game, deltaMs)— Phase 1: Sim-Zeit + Zeitlimit-Check, alle anderen Pipeline-Schritte (Vehicles, Contracts, Economy, Events) sind Phase 2/3/5 StubsconvertRealTimeToGameMinutes(deltaMs, timeScale)— utilitygetSimHoursElapsed(game)— utilityserialize(game)/deserialize(json)— ohne Listener (Autosave 7b)createGame(levelNum, {deterministic, seed})— neue Option für Tests- Internes
_setState()löst onStateChange-Callbacks aus
-
game.html komplett umgebaut:
- Leaflet-Karte mit Carto Positron (Atlas-Vorgabe), tap:true für iPad
- 13 Locations gerendert als CircleMarker pro Typ (CAPITAL grün/CITY grau/PORT blau/TERMINAL braun)
- Layer-Gruppen: Hauptstädte, Städte, Häfen, Terminals, Bahnnetz
- Layer-Control oben rechts (collapsed:false), Marker-Filter nach
visibleFromLevel <= visibleLocationLevelaus Level-Config - Bahnnetz als gestrichelte Polylines (5 Kanten Wien-München-Hamburg- Rotterdam-Paris-München)
- RAF-Loop ruft
tick(deltaMs)undupdateStatusUI() - Speed-Buttons (1×/2×/4×/8×) mit
aria-pressed-Toggle, ≥36px - Pause-Button mit kontextsensitiven Übergängen (READY→PLANNING→RUNNING ↔ pause/resume)
- Status-Leiste live: Sim-Zeit, Konto, Bilanz, Aufträge x/y, State
- Save/Load via localStorage (Phase 1 Skelett, Server-API in Phase 7)
- Autosave-Hook via onStateChange (localStorage)
- Sprachregel 4a durchgehend („Bearbeiter:in", „Simulation", „Durchgang", „Sim-Zeit") — nirgends „Spieler"/„Spiel"
-
test.html erweitert um Test 11 (10 Cases) Phase 1:
- 11.1 deterministic createGame → reproduzierbare sessionId+startTime
- 11.2 State-Übergänge INIT→LOADING_CONTENT→READY
- 11.3 startPlanning + startSimulation
- 11.4 tick(1000ms, 1×) → +1 Sim-Min
- 11.5 tick(1000ms, 4×) → +4 Sim-Min
- 11.6 paused tick → keine Zeit-Änderung
- 11.7 50× tick auf zwei Instanzen mit Seed 99 → identische simulationTime
- 11.8 onStateChange protokolliert alle 4 Übergänge
- 11.9 Zeitlimit überschritten → state=LEVEL_FAILED
- 11.10 serialize/deserialize Roundtrip + Listener-Reaktivierung
- Test 7 (Bahn-Dijkstra) erweitert um Wien→Paris (1220 km) und Wien→Rotterdam (1700 km via Hamburg, nicht via Paris)
-
noop-Strategie weiterhin lauffähig: noop nutzt eigenen Mini-Loop (
simHours += 1), keine engine.tick-Abhängigkeit → läuft ohne Phase-2-Implementierung weiter. Test 10 grün-erwartet. -
Mathematische Verifikation (Python 1:1): Tick-Konversion, Dijkstra-Pfade, Mulberry32 — alle neuen Cases verifiziert.
Verbliebene Stubs (Phase 2+): assignContract, calculateRoute,
useHint, applyMinigameResult, sowie die Strategien naive/greedy/optimal.
Nächstes (Phase 2): Auftrags-Generierung + Fahrzeug-Bewegung + Routen-Visualisierung → Level 1 spielbar Blocker: keiner — Atlas hat „keine weiteren Reviews bis Phase 1 fertig" gesagt, ich starte Phase 2 nach Thomas-Test Offen für Thomas:
- Browser-Test
http://localhost/geograsim/App/sims/logistik/test.html(Test 1–11, ~36 Cases) - Browser-Test
http://localhost/geograsim/App/logistik?level=1(Karte sichtbar, Pause-Button startet Sim-Zeit, Speed-Buttons schalten)
Tagesabschluss 2026-04-20 (03:30) — Phase 2 ausgeliefert + Header-Fix
Atlas-Phase-1-OK + grünes Licht für Phase 2 (03:00). Atlas hat mein Phase-1-Plan-§6 1:1 übernommen und „keine weiteren Reviews bis Phase 2 fertig" gesagt. Header-Klassen-Anfrage von 02:45 wurde nicht direkt beantwortet (Überschneidung), aber das Template ist die Wahrheitsquelle — Header habe ich selbst aufs Template-Pattern umgestellt (kein Klassen- Erfinden, nur 1:1-Übernahme).
Header-Fix (vor Phase 2)
- Klassen auf Template-Muster:
ggs-header-logo+ggs-header-logo-iconggs-header-logo-text+ggs-header-separator+ggs-header-moduleggs-header-badge+ggs-header-spacer+ggs-header-actions+ggs-speed/ggs-speed-btn+ggs-btn-ghost
- Pause-Button als
data-speed="0"integriert (Template-Vorschlag) - Lehrplan-Link
📚ergänzt (verweist auf modul-logistik.php#lehrplan-bezug) - Eigene CSS-Override-Regeln entfernt (DS macht das jetzt sauber)
- Speed-Button-Wahl steuert auch start (von PLANNING → RUNNING bei
>0)
Phase 2 — Engine
calculateRoute(game, originId, targetId, mode)— Phase-2-Strategie Luftlinie × 1.3, liefert Route mit Geometrie + Distanz + Dauer + Segments. Provider markiert alsairline_x1.3(Phase 3 ersetzt mit Hand-Polylines).assignContract(game, contractId, vehicleId)— Validierung, Routenberechnung, Vehicle springt zur Origin (kein Pickup-Drive in Phase 2), States werden gesetzt._updateVehicles(game, simMinutes)im tick — Routen-Interpolation, bei Ankunft Vehicle→IDLE, Contract→DELIVERED_completeContract— Verspätung berechnen, Erlös + Bonus−Fahrkosten−Strafe buchen, Contract in completedContracts, Notification, Auto-Folgeauftrag generieren (Phase-3-Vorgriff für L1-Spielbarkeit)seedInitialVehicles(game)— Level-Config-driven Vehicle-Erstellung (L1: 1× TRUCK_SMALL in Wien)seedInitialContracts(game)— Level-1: 1× Wien→Salzburg festtickerweitert um Erfolgsprüfung (Time-Limit-Erreichung mit minTarget → LEVEL_SUCCESS, sonst LEVEL_FAILED)
Phase 2 — Headless-Runner
naive-Strategie aktiviert: nimmt erstes OPEN ↔ erstes IDLE, tickt 5 Sim-Min/Iter bis state≠RUNNING. Nutzt opts.seeds wenn übergeben (für Tests ohne window.LOGISTIK_SEEDS).- runLevel ruft createGame mit deterministic+seed
- noop bleibt unverändert lauffähig (eigener Loop, keine engine.tick-Abhängigkeit)
Phase 2 — UI (game.html)
- Contracts-Panel zeigt Cards pro Auftrag mit Code, Strecke, km, Erlös, Frist, State-Badge. Klick selektiert (toggleable).
- Vehicles-Panel zeigt Cards pro Fahrzeug mit Name, Speed, Kapazität, Standort. Klick bei selected contract → assignContract.
- Routen-Polylines (durchgezogen, dunkelgrün) für jede activeRoute
- Fahrzeug-Marker als 🚚/🚆 (DivIcon), Position aus RAF-Loop
- Hilfestufe BLINK_EXACT (Phase 5 vorgegriffen): blinkende Ringe um Origin (gelb) und Target (rot) bei selected contract
- Toast-Notifications bei Delivery (mit Net-Betrag)
- Sprachregel 4a durchgehend (Aufträge, Bearbeiter:in, etc.)
Phase 2 — Tests (test.html)
- Test 12 (5 Cases) — calculateRoute Wien→Salzburg ≈ 326 km × 1.3
- Test 13 (8 Cases) — assignContract State-Übergänge + doppelte Zuweisung wirft
- Test 14 (3 Cases) — tick bewegt Vehicle (segmentProgress strikt zwischen 0/1)
- Test 15 (6 Cases) — Delivery + Erlös + Folge-Auftrag automatisch
- Test 16 (3 Cases) — latePenaltyOverride wird respektiert + analytics++
- Test 17 (5 Cases) — naive auf L1 schafft Akzeptanzkorridor (≥4 Aufträge, Profit ≥ +1000€, success=true)
- Test 10.3 angepasst: greedy wirft jetzt „Phase 2", naive ist aktiv
Mathematische Verifikation (Python 1:1)
- Wien-Salzburg airline = 250.82 km, × 1.3 = 326.06 km, 4.66 h @ 70 km/h
- Pro Auftrag: Net 792.27€ (1300€ Erlös − 507.73€ Fahrkosten)
- 24h / 4.66h = 5 Aufträge schaffbar
- Gesamtprofit: 3961€ > 3000€ Min-Ziel → success ✓
L1 ist spielbar. Im Browser: Klick auf Auftrag (blinkende Ringe) → Klick auf LKW → Fahrt beginnt → 1× oder 4×/8× Speed → LKW fährt nach Salzburg → Toast „Auftrag abgeschlossen +792€" → Folge-Auftrag erscheint.
Nächstes (Phase 3): Mehrfahrzeuge, Mehraufträge mit Variation, Kostenmodell für Miete/Standkosten, Hand-Polylines für 12 Hauptstrecken, Level 2 spielbar. Ziel: ~50% schaffen L2 mit greedy, ~70% mit optimal.
Blocker: keiner — Atlas hat „direkt Level 1 spielbar → Thomas- Browsertest → Phase 3" gesagt. Header-Klassen-Frage 02:45 ist faktisch durch Selbstkorrektur auf Template gelöst, aber Atlas könnte noch beanstanden falls anders gemeint.
Offen für Thomas:
- Browser-Test
App/logistik?level=1: 1 Auftrag links, 1 LKW rechts, klicken → blinkende Ringe → LKW klicken → Fahrt → Toast bei Ankunft → Folge-Auftrag → Bilanz wächst - Test-Harness
App/sims/logistik/test.html: 17 Gruppen, ~60 Cases, alle grün erwartet
Tagesabschluss 2026-04-20 (05:00) — Phase 3 ausgeliefert
Atlas-Wrapper-Patch war 04:00 fertig, Thomas hat Phase 2 live gesehen und sofort gefragt, ob die LKW Hauptstraßen statt Luftlinie fahren können — exakt Phase 3 nach Plan. Grünes Licht erteilt, gestartet.
Phase 3 — Hand-Polylines + Engine
App/assets/data/lg-routes-osm.json— 17 Hauptstrecken zwischen den 13 Locations mit handgepflegten Polyline-Stützpunkten an bekannten Knoten (St. Pölten, Linz, Brennerpass, Lille, Reims, etc.). Bidirektional. Polyline-Längen via Python verifiziert.engine.calculateRoutePhase 3 — Polyline-Lookup (Forward + Reversed), Fallback auf Luftlinie × 1.3. Provider-Markierung (osm_polyline/osm_polyline_reversed/airline_x1.3).- Pickup-Drive in
assignContract: wenn Vehicle nicht am Origin, zweistufige Route (Pickup + Delivery) - 4-Phasen-Trip in
_updateVehicles: pickup_drive → loading → delivery_drive → unloading. Mit Phase-Übertrag-Loop (kein Drift bei großen Ticks) _completeContractmitvehicle-Param: noEmpty-Bonus korrekt, Pickup-Fahrkosten zusätzlich,contract.pickupKmfür Tracking- Kostenmodell im tick (
_applyRunningCosts): Standkosten/h für IDLE-Vehicles, Miete/Tag für alle Vehicles - Auftrags-Variation deterministisch (Mulberry32 + Counter):
12
CONTRACT_TEMPLATES, L2/L3 ziehen daraus, L1 hardcoded auf Wien↔Salzburg-Pendel (vermeidet Leerfahrten, hält naive im Akzeptanzkorridor) seedInitialVehiclesverteilt auf Hubs (L1: Wien; L2: Wien/ München/Hamburg; L3: 5 Hubs)
Phase 3 — Headless-Runner
greedy-Strategie aktiviert: höchster rewardBase ↔ größtes Vehicle das passt
Phase 3 — Tests
5 neue Gruppen, 19 neue Cases (Test 18-22). Total 22 Gruppen / ~80 Cases.
Mathematische Sanity-Checks (Python)
- L1 Pendel mit airline-Fallback: 4 Trips × 792€ = 3169€ > 3000€ Min ✓
- L1 mit Polyline (kürzer): noch profitabler
- L2/L3 Akzeptanzkorridor: nicht erfüllt (siehe Balance-Hinweis unten)
Atlas-Wartepunkt
Wrapper-Erweiterung in logistik.php für lg-routes-osm.json
(siehe Atlas-Mail 2026-04-20-0500). Bis dahin fahren LKWs im Browser
noch auf Luftlinie × 1.3. Test-Harness unbetroffen (Inline-Seeds).
Balance-Hinweis (für künftige Tuning-Iteration)
L2/L3-Akzeptanzkorridor mathematisch noch nicht erfüllt. Pflichtenheft
gibt rewardBase=1000 fix (unabhängig von Container/Distanz). Mit
Pickup-Drive werden lange Strecken (>500km) verlustig. Tuning für
Phase 4+ (z.B. Reward proportional zur Distanz). Test 22 prüft nur
strukturelle Lauffähigkeit.
Offen für Thomas
- Atlas-Wrapper-Update abwarten, dann Browser-Test L1 (Pendel-Modus, Polyline-Routen sichtbar — LKW fährt entlang St. Pölten-Linz-Wels statt diagonal durch die Donau)
- Test-Harness
test.html: 22 Gruppen / ~80 Cases sollten alle grün
Tagesabschluss 2026-04-20 (06:00) — Phase 4a + Music
Music-Player aktiv
- 4 Tracks aus
.humanInput/Background Music/_claimed/kopiert nachApp/sims/logistik/sounds/music/:saddlewood-metronome.mp3(3 MB, mechanisch-rhythmisch)gears-and-marbles.mp3(3.2 MB, Steve-Reich-Stil)barbed-lullaby.mp3(3.2 MB)untitled-instrumental.mp3(2.9 MB)
.ggs-music-Markup im Header eingebaut (Pattern aus template.html)ggsMusicSetup-Funktion inline (gleicher Code-Pfad wie Klima/Fluss)- Default-Volume 22 %, localStorage
ggs-music-logistik
Phase 4a — Engine
- TRAIN-Routing:
calculateRoutenutzt für mode=TRAIN denrailShortestPath-Dijkstra überworldState.railnet. Wenn beide Locations Bahnknoten sind, kommt eine echte Mehr-Segment-Route raus (provider:rail_dijkstra), sonst Fallback auf Polyline/airline. Geometrie führt durch alle Bahnknoten. - Hafen-Schiffsankünfte:
_maybeGenerateShipArrival(game)läuft im tick, alle 6 Sim-Stunden ein Schiff (deterministisch via Counter). Generiert OPEN-Auftrag mit Origin=Hafen, Target=Hauptstadt-Pool rotierend. Code-PräfixSHIP-,narrativeTexterwähnt Hafen, NotificationSHIP_ARRIVED. Nur aktiv beicfg.portsEnabled=true. - Container-Standkosten:
_applyRunningCostsrechnet zusätzlich zu Vehicle-Standkosten/Miete auchcontainerStandCostPerHour × quantityContainers × simHoursfür jeden OPEN-Auftrag mit Origin am Hafen.
Phase 4a — Tests (3 neue Gruppen, ~10 Cases)
- Test 23 (5): TRAIN-Routing über railnet-Dijkstra (Wien→Hamburg via München = 1200 km, 2 RAIL-Segmente), Fallback wenn kein Bahnknoten
- Test 24 (4): Schiffsankunft-Generator (nach 7h Sim mit portsEnabled → SHIP-Auftrag + Notification)
- Test 25 (1): Container-Standkosten an Häfen (3 Container × 10€/h × 1h = 30€ pro Sim-Stunde abgezogen)
Total jetzt: 25 Test-Gruppen, ~90 Cases.
Phase 4b verschoben (Intermodal)
Vollständige intermodale Aufträge mit legs[]-Struktur und Multi-
Vehicle-Übergabe (LKW→Zug→LKW) sind komplexer als die anderen 3
Phase-4-Punkte zusammen. Phase 4a deckt die Basis-Strukturen ab
(Bahn-Routing + Hafen-Aufträge), 4b kommt als nächste Iteration:
- Contract-Schema um
legs: [{mode, originId, targetId}]erweitern - Engine-Logik für Übergabe zwischen Vehicles am Terminal/Hafen
- Container am Hafen warten auf Folge-Vehicle (Inland-Strecke)
- LOADING-Phase am Übergabepunkt mit echten Cargo-Transfer-Zeiten
- Lehrziel #13 (kombinierte Verkehre) wirklich erlebbar
Offen für Thomas
- Browser-Test App/logistik?level=1: Music-Player rechts oben sollte sichtbar sein (Tracks wählbar, ▶ startet)
- Browser-Test test.html: 25 Gruppen / ~90 Cases sollten alle grün
- Phase-4b-Entscheidung: jetzt oder erst nach L3-Tuning?
Atlas-Wartepunkte
- Wrapper-Erweiterung
lg-routes-osm.json(von Mail 0500, noch offen) - Music-Tracks-Bestätigung (von Mail 0540, „letzten paar" akzeptiert?)
Tagesabschluss 2026-04-20 (06:30) — Phase 4b + 5a ausgeliefert
Thomas: „Arbeite weiter, soweit du kannst." → Phase 4b (Intermodal-Engine) und Phase 5a (Event-Engine) komplett implementiert. Phase 5b (Hilfestufen-UI) auf Phase 6 verschoben — passt natürlich zu Sprachregel-Check + Leichte Sprache (alles UI-Polish).
Phase 4b — Intermodale Aufträge
- Schema: Contract bekommt optional
intermodal: trueundlegs: [{legNum, mode, originLocationId, targetLocationId, state, assignedVehicleId, routeId, departTime, arrivalTime}]. PluscurrentLegNumundcurrentLocationId(wo der Container gerade ist). _makeIntermodalContract(game, code, legs, containers, isExpress): Factory mit Aggregations-Daten (Gesamt-Distanz approx, Gesamt-Frist, rewardBase × 1.5 als Intermodal-Bonus).assignContract(game, contractId, vehicleId, legNum?):- bei intermodal:
legNumPflicht (sonst nimmt currentLegNum) - prüft Vehicle-Mode-Match zum Leg-Mode (TRAIN-Leg → TRAIN-Vehicle)
- setzt leg.state statt c.state
- bei intermodal:
_completeLeg(game, contract, legNum, route, vehicle):- markiert Leg als DELIVERED
- bucht Fahrkosten dieses Legs sofort (Reward kommt am Schluss)
- setzt currentLegNum/currentLocationId vor
- aktiviert nächsten Leg auf OPEN (Notification
LEG_TRANSFERRED) - bei letztem Leg: Reward + Bonus + Strafe in einem buchen, Contract als DELIVERED/LATE in completedContracts
_stepVehiclePhaseUNLOADING: erkennt intermodal und ruft_completeLegstatt_completeContract
Wichtig: Strategien (naive/greedy) sind Phase 4b NICHT angepasst — sie würden auf intermodal-Aufträgen mit Mode-Mismatch crashen. Phase 4c oder Phase 5 für Strategy-Anpassung. UI ebenfalls noch nicht intermodal-tauglich; Tests testen explizit via _makeIntermodalContract.
Phase 5a — Event-Engine
_maybeGenerateEvents(game, simMinutes): würfelt deterministisch via Mulberry32 (game.seed ^ 0xE7E7+ Counter_eventsRngCalls). Pro Sim-Stunde-Block + EVENT_TYPE:prob = baseProb × eventProbabilityMultiplier- EVENT_RULES (aus PH 65.5): TRAFFIC_ACCIDENT 5 % Speed×0.5, SNOW 10 % Speed×0.7 (Alpen), PORT_DELAY 8 % Loadtime×1.5
- Event-Dauer: 30-120 min (deterministisch via 2. Würfel)
_expireEvents(game): filtert abgelaufene Events_vehicleSpeedMultiplier(game): kombiniert alle aktiven Events multiplikativ → wirkt im_stepVehiclePhaseaufroute.totalDurationMinutes- Notifications:
EVENT_STARTEDmit Emoji-Message (🚧 Unfall, ❄ Schnee, ⚓ Hafenüberlastung)
Phase 5b — Hilfestufen-UI verschoben auf Phase 6
contract.hintMode ist schon im Schema (Phase 0/2), BLINK_EXACT ist
visuell umgesetzt (Phase 2). Die anderen 4 Stufen (SHOW_COUNTRY,
SHOW_REGION, DISTANCE_FEEDBACK, NONE) brauchen UI-Erweiterung
und passen natürlich zu Phase 6 (UI-Polish + Sprachregel + Leichte
Sprache) — alle drei drehen an der Darstellungs-Schicht.
Phase 4b + 5 — Tests
5 neue Cases:
- Test 26 (4 Cases): Intermodal-Schema (legs[], States)
- Test 27 (8 Cases): Multi-Leg-Trip (Rotterdam_Hafen→Hamburg→München)
- Test 28 (3 Cases): Event-Generierung deterministisch + reproduzierbar
- Test 29 (1 Case): Manuelles Event reduziert Vehicle-Speed
- Test 30 (2 Cases): Events laufen nach Dauer ab
Total jetzt: 30 Test-Gruppen, ~110 Cases.
Was noch offen ist (Phase 6, 7, weitere)
- Phase 6: Hilfestufen-UI, 1× Minigame (An-die-Rampe-Einparken),
Sprachregel-4a-Check aller UI-Texte, Leichte-Sprache via
pickText(), Glossar-Begriffs-Anbindung - Phase 7: Lehrkraft-Konfiguration (über Admin-Tool), Analytics-Dashboard (Kennzahlen aus PH 23.2)
- Strategie-Anpassung: greedy für intermodal, optimal-Strategie
- Balance-Tuning für L2/L3 (rewardBase distanzproportional?)
Browser-Tests offen
- Test-Harness: 30 Gruppen / ~110 Cases sollten alle grün
- Live-UI: Music-Player + LKW-Polylines (nach Atlas-Wrapper-Update)
Tagesabschluss 2026-04-20 (07:00) — Phase 6 ausgeliefert
Thomas: „Mach weiter. Direkt Phase 6 machen." → UI-Polish komplett in 3 Subphasen.
Phase 6a — Sprachregel + pickText + Hilfestufen + Glossar + Events
- Sprachregel-4a-Audit: alle UI-Texte sauber (nur interne Doc-Comments enthalten „Spielzustand"/„spielbar" — laut Atlas-Briefing erlaubt)
- pickText-Helper mit Easy-Detection:
?easy=1URL-Param oderlocalStorage 'logistik:easy'='1'schaltet auf Leichte-Sprache-Variante - GLOSSAR-Fallback (Pattern aus Fluss): 16 Begriffe inline definiert (Container, Intermodal, Umschlag, Luftlinie, Disposition, Frist, Leerfahrt, Standkosten, Bahnterminal, Hafen, Routing, Spedition, Logistikkette, Auftrag, Fahrzeug, Logistik). Wenn Atlas/Glossar später DB-API liefert → Fallback bleibt als Backup.
- Glossar-Click-Handler:
.ggs-glossar-popupPattern aus Design-System - Glossar-Markups in Auftrags-Karten + Hint-Texten + Didaktik-Text
- 5 Hilfestufen visuell (PH 10.3):
- BLINK_EXACT: ✓ Origin (gelb) + Target (rot) blinken (war Phase 2)
- SHOW_COUNTRY: alle Locations im selben Land wie Target leuchten
- SHOW_REGION: alle Locations in selber Region leuchten (sanftes Blau)
- DISTANCE_FEEDBACK: Skelett (UX-Mechanik kommt mit Phase 7+)
- NONE: nichts angezeigt
- Event-Panel im Didaktik-Bereich: aktive Events als Pills („🚧 Unfall · noch 25 min", „❄ Schnee · noch 60 min")
- pickText in Toasts: standard + easy für Auftrag-Zuweisung, Delivery-Result, Fehlermeldungen
- CSS für
[data-glossar]: dotted-Underline + cursor:help
Phase 6b — Intermodal-UI
- Auftrags-Karte erkennt
c.intermodalund zeigt Leg-Liste als Pills (durchgestrichen=DELIVERED, fett-grün=OPEN, grau=WAITING) - 🔗-Symbol im Auftrag-Titel bei Intermodal
- Mode-Filter im Vehicles-Panel: bei selected intermodal-Auftrag werden Vehicles, deren Mode nicht zum aktuellen Leg passt, als „busy" angezeigt mit Hint „benötigt: 🚆 Zug" / „benötigt: 🚚 LKW"
- Click-Handler übergibt
currentLegNumanassignContract - Bei Intermodal: Auftrag bleibt selected nach Vehicle-Wahl (für Folge-Legs)
- Demo-Hook:
?demo-intermodal=1triggert Beispiel-Auftrag Rotterdam_Hafen → Hamburg → München bei L3 - Strategien angepasst: naive/greedy filtern intermodal-Aufträge raus (Phase 6c oder Tuning-Iteration für intermodal-fähige Strategien)
Phase 6c — Minigame „An-die-Rampe-Einparken"
- Engine:
applyMinigameResult(game, result)implementiert (war Stub):- Speichert
loadingTimeFactorausresult.metadataingame._loadingTimeModifier - Wirkt auf nächste LOADING-Phase (in
assignContract), danach Reset auf 1 - Trackt
analytics.minigamesPlayed+minigamesSuccessful - Generiert
MINIGAME_DONE-Notification
- Speichert
- UI: Modal mit Canvas (420×200), Top-Down-View
- Steuerung: Touch-Buttons ⬅ ➡ + 📦 Andocken (iPad-tauglich, ≥44px)
- Bewertung:
- LKW-Vorderkante in 12 px um Rampen-Mitte → perfect → factor 0.8 (−20 %)
- 12-30 px → ok → factor 1.0
-
30 px → miss → factor 1.3 (+30 %)
- PH 65.9 Werte exakt umgesetzt
- Trigger-Button 🎮 im Header sichtbar wenn
cfg.minigamesEnabled=true(L2/L3) - pickText für alle Minigame-Texte (standard + easy)
Phase 6 — Tests
- Test 31 (4 Cases): applyMinigameResult setzt Modifier, wird in nächster LOADING-Phase angewendet (5 × 0.8 = 4 min), dann Reset
- Test 32 (1 Case): Minigame-Fail erhöht Loading auf 6.5 min (5 × 1.3)
Total jetzt: 32 Test-Gruppen, ~115 Cases.
Was Phase 6 NICHT enthält
- Strategien-Anpassung für intermodal (Phase 6d / Tuning)
- DB-Glossar-API (Atlas + Glossar-Instanz)
- DISTANCE_FEEDBACK voll umgesetzt (braucht Klick-zum-Wählen-UX)
- Keine API-Endpunkte
- Kein Lehrkraft-Konfig-UI (Phase 7)
Browser-Tests offen
- test.html: 32 Gruppen / ~115 Cases
- App/logistik?level=1: Glossar-Begriffe (gepunktete Unterstreichung) anklickbar; Music-Player
- App/logistik?level=2:
- Minigame-Button 🎮 im Header
- App/logistik?level=3:
- Bahn-Layer + Häfen + Schiffsankünfte + Events sichtbar im Panel
- App/logistik?level=3&demo-intermodal=1:
- intermodaler Demo-Auftrag mit 2 Legs (LKW Rotterdam_Hafen→Hamburg, Zug Hamburg→München)
- App/logistik?level=1&easy=1: Leichte-Sprache-Modus aktiv
Atlas-Wartepunkte
- Wrapper-Erweiterung
lg-routes-osm.json(Mail 0500) - Glossar-Begriffe (Anfrage 0010, Atlas koordiniert)
- Music-Tracks-Bestätigung (Mail 0540)
Tagesabschluss 2026-04-21 (Phase 8) — Multi-Contract-Tour
Thomas's Konzept übernommen: Vehicle-first-Lademodus.
- Klick auf IDLE-Vehicle → Lademodus aktiv (Banner + Laderaum-Slots)
- Klick auf OPEN-Auftrag → wandert in den LKW (Cargo-Emoji im Slot)
- „🚀 Fahrt starten" → Multi-Stop-Tour beginnt
Engine-API neu:
loadContract(game, vehicleId, contractId)— Kapazität-Check, Mode-Check, Contract → RESERVEDunloadContract/cancelLoading— vor Fahrt-StartstartTour(game, vehicleId)— baut Stops (alle Pickups erst, dann alle Dropoffs in Klick-Reihenfolge), konsolidiert aufeinanderfolgende Stops am gleichen Ort, berechnet Routen pro Segment, startet erste Phase
Trip-Phase neu:
tour_driving(zwischen Stops) undtour_handling(an einem Stop laden/entladen)_stepVehiclePhasedurchläuft Stops sequentiell, bucht Fahrkosten pro Segment sofort, Reward bei Dropoff_endToursetzt Vehicle zurück auf IDLE
Cargo-Typen mit Emojis:
lg-cargo-types.jsonumemoji-Feld erweitert (📱 Elektronik, 👕 Kleidung, ⚙️ Maschinen, 🥫 Lebensmittel, 🧪 Chemie, 🔩 Fahrzeugteile, 🪵 Holz/Papier, 🪨 Rohstoffe)CONTRACT_TEMPLATEShaben jetztcargoTypeIds-Liste pro Strecke_nextContractTemplatezieht deterministisch einen Cargo-Typ- Laderaum-Slots zeigen das Cargo-Emoji des belegenden Auftrags
UI-Lademodus:
- Vehicle-Card zeigt Banner + Laderaum-Grid (cap-viele Slots, gefüllt mit Cargo-Icons)
- „🚀 Fahrt starten"-Button (disabled bei leer) und „↺ Abbrechen"
- Klick auf RESERVED-Auftrag macht nichts (Card ist busy-styled)
- Wechsel zu anderem Vehicle: altes Vehicle wird automatisch entladen (cancelLoading)
Bestehende Pfade unangetastet:
assignContractbleibt für intermodale Aufträge (selectedContractId-Pfad)- Engine-Tests 13–17 nutzen weiter assignContract → laufen unverändert
- Intermodal hat eigenen 4-Phasen-Trip (pickup_drive/loading/delivery_drive/unloading), nicht den neuen Tour-Pfad
Was Phase 8 NICHT enthält (Phase 9 / nice-to-have):
- Tour-Route-Vorschau auf der Karte vor „Fahrt starten" (geplante Stops als gestrichelte Linie)
- Klick-Animation „Container wandert in den LKW"
- Naive/greedy-Strategien wurden noch nicht angepasst (filtern intermodal+RESERVED)
- Optimierungs-Button („Reihenfolge optimieren ✨")
- Während-der-Fahrt-Nachladen (an Stops zusätzliche Aufträge dazunehmen)
Browser-Test:
- http://localhost/geograsim/App/logistik?level=3
- Zug-Card klicken → Banner „Lademodus aktiv" + 20 Slots
- Aufträge nacheinander reinklicken — Container füllen sich mit Emoji
- „🚀 Fahrt starten" — Zug fährt erst alle Pickup-Orte, dann alle Dropoff-Orte ab
- Bei selber Origin: Stops werden konsolidiert (1 Pickup für mehrere Aufträge)
Tagesabschluss 2026-04-20 (08:00) — Phase 7a: Analytics + Balance-Tuning
Thomas: „mach weiter" → Phase 7 angepackt. Teile, die Plattform-Domain sind (Lehrkraft-Admin + API-Endpunkte + DB-Migration), an Atlas übergeben (Mail 0800). Modul-Seite von Phase 7 ist fertig:
Balance-Tuning: rewardBase distanzabhängig
_computeReward(distanceKm, isExpress)in Engine- PH-Base +
max(0, (km - 300) × 1.5)Zuschlag - Kurze Strecken bleiben PH-kompatibel (Wien-Salzburg: 1000→1039€)
- Lange Strecken profitabel (Wien-Hamburg: 1000→2350€)
- Intermodal-Bonus × 1.5 bleibt erhalten
- Python-verifiziert: L1-Pendel-naive bleibt schaffbar (845€ × 4 = 3380€)
Analytics-Tracking in Engine
totalRewardEarned,totalPenaltyPaid,totalFareCostPaidrunningCostsTotal(war schon da)contract.durationHourspro abgeschlossenem Auftrag
UI — Analytics-Panel
- Toggle-Button 📊 oben rechts auf der Karte
- 12 Kennzahlen live (Aufträge, Leerfahrtenquote, Verspätungsquote, Ø-Net/Auftrag, Erlöse, Fahrkosten, Strafen, Standkosten+Miete, Minigame-Erfolg, Bilanz/Profit)
- Live-Update im RAF-Loop bei offenem Panel
UI — End-Screen
- Overlay bei State-Wechsel zu LEVEL_SUCCESS / LEVEL_FAILED
- Success in grün, Fail in rot
- Gekürzte Stats-Liste (5 wichtigste Werte)
- pickText für standard/easy
- „Neuer Durchgang"-Button reloaded Seite
- Via
onStateChange-Hook automatisch getriggert
Was bei Atlas liegt (Phase 7b)
- Lehrkraft-Admin-Tool (admin-levels.html erweitern vs. separat)
- API-Endpunkte
App/php/api/logistik-*.php— ich kann selbst, erwarte Go - DB-Migration
lg_contracts_log— Freigabe vom Schema - Glossar-API-Anbindung falls die 13+ Begriffe angelegt sind
Offen für Thomas
- Browser-Test L1/L2/L3: Analytics-Button 📊 rechts oben, End-Screen nach Zeitlimit oder Min-Ziel-Erreichen
- Die Balance-Tuning-Änderung macht L1 leichter, L2/L3 besser spielbar
Tagesabschluss 2026-04-20 (07:30) — UX-Iteration „Fahrzeug-Auftrags-Verbindung"
Thomas: „wenn der Auftrag angenommen wurde und das Fahrzeug unterwegs ist, wäre es schön, wenn irgendwo erkennbar wäre, dass diese Verbindung wirklich vorliegt." → drei Mechanismen ineinandergreifen lassen.
Was neu ist
- Vehicle-Card zeigt Trip-Info bei MOVING/LOADING/UNLOADING:
- Phase-Label („🟡 Leerfahrt zum Abholen", „📦 Lädt", „🟢 Unterwegs", „📥 Lädt ab")
- Auftrag-Code + Strecke („C-001 · Wien → Salzburg")
- Progress-Bar bei Fahrten (live aus
v.segmentProgress) - ETA („ETA 14:32") oder Restdauer („noch 3 min") je nach Phase
- Vehicle-Marker mit Hover-Tooltip (Leaflet
bindTooltip, sticky): Name, Phase, Auftrag, Prozent-Fortschritt - Klickbares Pairing:
- Klick auf Vehicle-Card oder -Marker → selectedVehicleId
- Zugehörige Contract-Card bekommt
linked-pair-Highlight (blauer Ring) - Vehicle-Card bekommt
linked-Highlight (grüner Ring) - Zugehörige Route wird auf der Karte dicker+kräftigrot, andere Routen werden gedimmt
- Klick zentriert die Karte auf's Fahrzeug
- Erneuter Klick deselect
- Auto-Deselect: wenn Vehicle IDLE wird (Delivery fertig) → Selection automatisch gelöscht
CSS-Klassen neu
.lg-trip-info(+.pickup,.loading) — Trip-Box unter Vehicle-Titel.lg-progress-bar+.lg-progress-fill(+.pickupfür gelb).lg-card.linked(grün) +.lg-card.linked-pair(blau)
Keine neuen Tests
UX-Erweiterung (visuell), kein Engine-Change. Test-Gruppen bleiben bei 32.
Offen für Thomas
- Browser-Test App/logistik?level=1:
- Auftrag klicken → LKW klicken → Fahrt startet
- Jetzt: Vehicle-Card zeigt „🟢 Unterwegs · C-001 · Wien → Salzburg · ETA ..." mit Progress-Bar die mit 1×/4×/8× Speed füllt sich live
- Marker-Hover auf der Karte zeigt Tooltip
- Marker-Klick zentriert Karte + beide Cards sind farblich verbunden
- Bei L2/L3 analog — mit mehreren aktiven Trips siehst du die Fokus- Route hervorgehoben, andere gedimmt
Tagesabschluss 2026-04-22 — UX-Polish-Sprint + Atlas-Phase-7b-Entscheidungen
Neue Atlas-Nachricht (1200, gelesen + quittiert)
2026-04-22-1200-phase7-entscheidungen-und-db.md — Atlas hat nach
2 Tagen Pause alle drei offenen Punkte entschieden:
- Lehrkraft-Admin: Atlas erweitert
App/admin-levels.html(zentrales Tool). Mein Beitrag:App/sims/logistik/admin-fields.jsonmit Feld-Beschreibungen aus balance-matrix.md §5. - API-Endpunkte: Ich baue selbst, Pattern aus
App/php/api/glossar.php. Drei Endpunkte:logistik-sessions.php,logistik-saves.php,logistik-analytics.php. Security: Session-ID gegenstudent_sessionsvalidieren. Kein formales Review, ich committe wenn zufrieden. - DB-Migration
lg_contracts_logerledigt. Schema erweitert umintermodal,route_distance_km,route_mode. Meister pingt Atlas für Produktions-Replikation. - Glossar-API: Fallback bleibt, Switch wenn Glossar liefert. Pattern
kommt in
App/docs/module-interface.md.
Thomas-Frage „nächstes Modul" → Atlas sagt: erst nach Phase 7b.
Phase 8 + UX-Iterationen (heute + gestern)
- Multi-Contract-Tour: Vehicle-first-Lademodus, Cargo-Icons (📱👕⚙️🥫🧪🔩🪵🪨), Klick-Reihenfolge-Tour (Pickups zuerst, dann Dropoffs; konsolidiert aufeinanderfolgende Stops am gleichen Ort), Laderaum-Slot-Visualisierung, „🚀 Fahrt starten" / „↺ Abbrechen"
- Container-Visualisierung: bis 6 Container als einzelne 📦-Symbole, ab 7 als „N× 📦". Mit Glossar-Popup (TEU + metrische Maße)
- Scale-Bar auf Leaflet-Karte (unten-links, metrisch, bis 100 km)
- Pro-Vehicle-Farben (8 Palette-Farben): Vehicle-Card-Dot, Marker-Ring, Route-Farbe (durchgezogen Lieferfahrt, dünn gestrichelt Pickup-Leerfahrt)
- Event-Symbole auf der Karte: 🚧 Unfall (Mittelpunkt einer aktiven Route), ❄ Schnee (Alpen-Region ±0.8°), ⚓ Hafenüberlastung (am Hafen)
- Rote Routen bei Verspätung (dashArray, überschreibt Vehicle-Farbe)
- Analytics-Panel gedämpft (1 Hz statt 60 Hz), Status-Leiste 4 Hz
- Farbleitsystem: OPEN grün · PICKUP/LOADING/IN_TRANSIT orange · DELIVERED blau · LATE rot · WAITING beige. Deutsche Labels mit pickText
- State-Labels deutsch: „offen"/„Abholung läuft"/„unterwegs"/„geliefert"/...
- Vehicle-Auftrag-Verbindung: Klick auf Vehicle (trip-aktiv) oder
Marker → Fokus-Route rot-dick, andere gedimmt, passende Contract-Card
mit blauem Ring (
linked-pair). Vehicle-Card mit Progress-Bar + ETA - Analytics-Panel + End-Screen (Phase 7a)
- Balance-Tuning (Phase 7a + 8):
_computeRewarddistanz-proportional- Container-Komponente (+250 €/zusätzl. Container), CONTRACT_TEMPLATES auf mehr 1-Container-Ranges (damit kleiner LKW nützlich wird)
- Drei-Kommastellen-Fix:
fmtEuro()+fmtEuroSigned()runden überall auf ganze Euro (Status, Toast, Analytics, End-Screen)
Minigame-Komplettumbau (mehrere Iterationen heute)
- Grüne Zielzone (LKW-Größe + 3 px Toleranz), sichtbar schraffiert mit „🎯 Hier parken"-Beschriftung
- Referenz-Miniaturen (3× 130×70 Canvas): ✅ Rückwärts · ❌ Vorwärts · ❌ Schief
- Countdown 3:00 rückwärts, MM:SS-Format, warnt bei <60 s orange, <30 s rot
- Auto-Andocken sobald 0,3 s stabil in grüner Zone + rückseitig + langsam
- Rückseitig-Pflicht: Nur angle ≈ 180° (Heck zur Rampen-Rückwand) zählt als „richtig"
- Live-Dock-Status: „✓ Zone · ✗ Heck zur Rampe (45°) · ✓ still"
- Crash-Szenarien → Game Over, factor 1.5:
- Anderes Fahrzeug rammen
- Bucht-Wand mit v>55 UND tiefem Overlap
- Zeitablauf (3 min)
- Active Mover ab L2 sichtbar im Feld: fahrendes Fahrzeug mit Waypoints
- sanfter Lenkung (Math.atan2 + max-turn-rate), wraps am Rand
- Zeit → Ladezeit-Faktor: <15 s → 0.7× / 15-30 s → 1.0 / 30-60 s → 1.2 / 60-180 s → 1.3 / Crash/Timeout → 1.5
- LKW-Optik verbessert: Kabine + Auflieger, Frontscheibe, Scheinwerfer, 6 Räder mit gelenkten Vorderrädern, Schatten
- Web-Audio-Sounds (synthesized, kein externer File nötig):
- Engine-Brummen: Sägezahn 55-200 Hz, Volume skaliert mit v
- Brems-Quietschen: Bandpass-Rauschen 0.25 s Burst bei abruptem v-Abfall
- Crash: tieffrequenter Sinus-Sweep + Lowpass-Impuls
- Musik-Auto-Start: Hauptmusik wird getriggert wenn Modal öffnet (click auf #ggs-music-toggle falls nicht playing)
- Buttons: „↺ Neu starten" (gelb-warm, 46 px hoch) + „Fertig · Schließen" (dunkelgrün), beide groß und touch-tauglich
- Andocken-Button entfernt (Auto-Detection ersetzt Manual-Check)
Offene Arbeitsliste (Phase 7b — Atlas-Reihenfolge)
App/sims/logistik/admin-fields.json— Feld-Beschreibungen aus balance-matrix.md §5 (15 Min Arbeit)App/php/api/logistik-sessions.php— POST start/end, GET statusApp/php/api/logistik-saves.php— POST save, GET load (gegengame_saves.save_dataJSON, Engineserialize()schon bereit)App/php/api/logistik-analytics.php— POST inlg_contracts_log(Schema Atlas bereits angelegt)- Analytics-Logging in
_completeContract-Hook — pro Delivery POST an Analytics-API
Nicht-Blocker-Wartepunkte
- Wrapper-Erweiterung
lg-routes-osm.json(Mail 0500) — Atlas hatte bestätigt 0400 als Tile-Proxy-Patch, Routes-Seed aber weiterhin offen. Browser-LKW fahren weiterhin Luftlinie × 1.3 (Fallback). Tatsächlich:engine.loadContentliestwindow.LOGISTIK_SEEDS.routesOsmfalls gesetzt → wenn Atlas den Wrapper erweitert, greift Polyline-Routing automatisch. - Glossar-API-Pattern (Atlas koordiniert mit Glossar-Instanz)
Browser-Test jetzt
- http://localhost/geograsim/App/logistik?level=2: Multi-Tour, Minigame 🎮 mit Countdown + Sounds + Mover
- http://localhost/geograsim/App/logistik?level=3:
- Bahn + Häfen + Events + Schiffsankünfte + schnellerer Mover
2026-04-22 ~14:00 — Phase 7b ausgeliefert (nach Atlas-12:00-Mail)
Gebaut
-
App/sims/logistik/admin-fields.json— alle 19params-Keys aus balance-matrix.md §5 mitlabel,labelEasy,type,unit,min/max/step,options,default,help. Gruppiert in 7 Abschnitten (Wirtschaft, Auftragslage, Fahrzeugpool, Didaktik & Hilfen, Ereignisse, Verkehrstraeger, Sonstiges). Bonus:availableVehicleTypesalsmultienum,levelNameEasyalstextfür Leichte Sprache. -
App/php/api/logistik-sessions.php— POST start/end, GET status. Persistiert ohne neue Tabelle viagame_savesmit Namespace-Keyslogistik:active-attempt/logistik:history(Ring-Puffer letzte 20 Durchgänge). Security: Cookie-Session gegenstudent_sessionsvalidiert. -
App/php/api/logistik-saves.php— GET/POST/DELETE. 5 Slots (1–5) via Keyslogistik:save:<slot>. 500 KB-Limit. Baut auf generischergame_saves-Tabelle auf — keine Duplikat-Tabelle zusaves.php. -
App/php/api/logistik-analytics.php— POST inlg_contracts_log(Atlas-Schema mit intermodal + route_distance_km + route_mode). GET liefert 3 Scopes:me(eigene letzten 50),class(Lehrer-only, pro Session),level(Lehrer-only, pro Level-Aggregation). -
Engine-Hook:
game.pendingAnalyticsals neue Queue._pushAnalyticsEntry()wird in_completeContract(Single) und_completeContractMulti(Tour) aufgerufen. Engine selbst macht keinen Netz-Call — bleibt in Node/Browser gleich testbar. UI drainiert die Queue alle 2s und POSTet (best-effort). -
game.html-Integration —
LG_API-Helper: fire-and-forget mitcredentials: same-origin, 401 → bis Session-Ende offline. Auf Game-Init:startAttempt(levelNum). Auf LEVEL_SUCCESS/FAIL:endAttempt(success, stats)+ Last-Drain der Analytics. Save/Load-Buttons jetzt Server-first mit localStorage-Fallback + Leichte-Sprache-Toasts.
Security-Minimum (wie Atlas vorgegeben)
- Jeder POST validiert Session-ID aus
ggs_session-Cookie gegenstudent_sessions-Tabelle (nicht nur Cookie-Präsenz) - Keine Fremd-Session-IDs schreibbar —
session_idkommt IMMER aus Server-Cookie, nie aus Request-Body - DELETE/GET auf Saves nur für eigene Session
class/level-Analytics-Scopes nur mitrequireTeacher()
Offene Punkte (an Atlas-Review)
logistik-saves.phplegt nicht in einer eigenen Tabelle ab, sondern namespaced im vorhandenengame_saves. Falls du stattdessen einelg_saves-Tabelle willst, Migration + Refactor-Patch.logistik-sessions.phpspeichert Aktiv-Attempt ebenfalls ingame_saves. Einfach, kein Schema. Falls du reportingfähigelg_attempts-Tabelle willst, sag Bescheid.- Ich habe keinen Browser-Test gemacht — es hängt daran, ob die bestehende
ggs_session-Cookie auch unter/App/logistik?level=1mitkommt (sollte dankBASE_PATH-Konfiguration, aber ungeprüft).
PHP lint
/c/xampp/php/php.exe -l App/php/api/logistik-sessions.php → OK
/c/xampp/php/php.exe -l App/php/api/logistik-saves.php → OK
/c/xampp/php/php.exe -l App/php/api/logistik-analytics.php → OK
Was Atlas jetzt tun kann
- Admin-UI gegen
admin-fields.jsonbauen — alle Feld-Metadaten stehen - Review der 3 PHP-Endpunkte, besonders: ist die
game_saves-Kooptierung für Sessions/Saves ok oder dedizierte Tabelle? - Meister anpingen, damit das
lg_contracts_log-Schema auf Produktion ist - Glossar-API — sobald die 13 Begriffe da sind, einbauen (Inline-Fallback in game.html funktioniert bis dahin)
2026-04-23 — Heute gebaut (lange Session)
Neu-Mails von Atlas (beide gelesen)
- 2026-04-22 12:30 ElevenLabs-Sound-Pipeline: zentrales Script
App/scripts/generate-sounds.py, API-Key liegt, PatternApp/sims/logistik/scripts/sounds-list.json. Vorgeschlagene Liste mit 22 Sounds (~3-5 €). Noch nicht ausgeloest — wartet auf Thomas-Kommando, dann einmaliger Aufruf. - 2026-04-23 11:00 Integrations-Auftrag: Logistik ist Referenz. Drei Punkte: (a) mode-check im Wrapper (logistik.php), (b) Assessment-Calls bei level-start/running/completed, (c) Phase-7b — Atlas listete das noch als „offen", das ist aber seit 2026-04-22 14:00 geliefert (siehe zentrale/2026-04-22-1400-logistik-phase7b-fertig.md). Atlas hat noch nicht reviewt.
Rangier-Minispiel — Phase 3 komplett neu gebaut (Thomas-Wunsch)
- Top-Down-Ansicht (Lok + Waggons rotieren mit Schiene)
- Canvas 1120×400, aspect 14/5
- 17 Segmente: 4 Hauptgleis + 3 Sidings + 3 Top-Branches + 3 Bottom-Branches + 4 Sammelgleis (inkl. 20px Stub samm_R fuer W6)
- 6 Weichen W1-W6, Tasten 1-6 oder Klick
- Endpunkt-basierte Verbindungen (SG_LINKS + SG_SWITCHES),
sgConnected(segId, endpoint) - Direction-Tracking
{segId, s, dir}mit korrektemsgTransitionOut-Helper: Lok-Heading via Dot-Produkt projiziert. Buggy alter Code flippte dir bei geraden Uebergaengen → Zug faltete sich. Fix verifiziert. - Consist-Modell mit Items-Array, auto-Kupplung am Wagen-Ende (nicht an Lok-Nase → Lok-Front blockiert mit Warnung)
- Entkupplung per ✂-Klick in Luecken (nur im Stillstand, senkrecht vom Gleis gezeichnet)
- Waggon-Labels
#1 #2 #3 #4statt Stadt-Emojis (Thomas-Wunsch — klarer) - Switch-Warning: roter pulsierender Ring + Web-Audio-Warnton (2× 880Hz Square) wenn: Lok faehrt gegen Sackgasse / Lok-Front rammt geparkte Wagen / Weiche umschalten wenn Zug drauf
- Zeit-Bonus: < 4 Minuten →
timeBonus: trueimapplyMinigameResult-Result
L1-Innen-Progression (Thomas-Wunsch: steigernd)
game.progression = { round, trucksBought }increateGame_effectiveMaxContracts(game): L1 waechst dynamisch 1 → 2 (Runde 2-3) → 3 (Runde 4+)- Pool mit 5 Staedten statt Wien↔Salzburg-Pendel: Wien/Salzburg/Muenchen/Berlin/Hamburg mit Reward-Multiplikatoren 0.8–1.7
- Staffel-Freischaltung: Runde 1-2 nur
mult ≤ 1.0, Runde 3-4 ≤ 1.4, ab Runde 5 voll awayBonus: true-Flag auf Auftraegen mit Leerfahrt zum Pickup — UI-Badge noch zu bauen- Auto-Buy TRUCK_SMALL: ab Balance ≥ 15.000 € spawnt automatisch neuer Kleiner LKW (Kosten 5.000 €), max 3 Fahrzeuge
- Runden-Increment in BEIDEN
_completeContract*-Pfaden
Balance-Regel R-1 (Startbudget-Runway)
- Formal:
startBudget ≥ 1.5 × (rental×vc + idle×vc×12) - L3 verletzt R-1 (2.500 € startBudget vs. 4.650 € benoetigt)
- L1/L2 passieren
- Python-verifiziert: L3-Runway 0.81–0.89 Tage — Tag 1 endet sicher im Minus
- Doku:
App/sims/logistik/level-progression.md(L1-Design §1 + L3-Analyse + R-1 §2)
3 neue zentrale-Mails an Atlas (alle offen)
- 2026-04-22 14:30 ElevenLabs-Frage — von Atlas beantwortet (Pipeline-Doku, s.o.)
- 2026-04-23 17:00 Warnton-Asset (Heli-Ton wiederverwenden?) + Konzept „Minispiel-an-Fahrt-Koppeln" (bonus auf Lade-/Entlade-Zeit)
- 2026-04-23 17:30 L3-Balance kaputt + Regel R-1 zur Pruefung + 3 Fix-Optionen (Empfehlung: startBudget 2.500 → 5.000)
Was auf Atlas wartet
- Admin-UI gegen
admin-fields.json(von Phase 7b) - Review der 3 PHP-Endpunkte (game_saves-Kooptierung ok?)
- Meister-Ping fuers
lg_contracts_log-Schema auf Produktion - Entscheidung L3-Balance (A/B/C aus 17:30-Mail)
- Daumen hoch fuer R-1 als Invariante
- Heli-Warnton-Pfad freigeben
- Buy-in fuer Minispiel-an-Fahrt-Koppeln-Architektur
Was auf Thomas wartet (optional, kein Blocker)
- Sounds generieren:
python App/scripts/generate-sounds.py logistiknachdemsounds-list.jsonunterApp/sims/logistik/scripts/angelegt ist (kostet 3-5 € ElevenLabs-Kontingent) - Entscheidung ob L1-UI-Badges fuer Runde + awayBonus dazu sollen
Offene Arbeit bei mir (wenn Atlas freigibt)
- Integrations-Auftrag (mail 23.04 11:00): mode-check im logistik.php + Assessment-Calls
sounds-list.jsonanlegen + Pipeline-Run (auf Thomas-Kommando)- End-Screen auf
.ggs-endscreen-Komponente umstellen (sobald Atlas die Inbox-Meldung schickt)
2026-04-23 — Nachtrag (Integrations-Auftrag + Polish)
Integrations-Vertrag Kap. 6 umgesetzt
- logistik.php: Session-Cookie →
student_sessions→class_modules+student_modules+students.easy_language. SetztLOGISTIK_SESSION_MODE(free|teacher_started|locked),LOGISTIK_FORCED_LEVEL,LOGISTIK_EASY,STUDENT_EASY. Locked-Fall: HTTP 403 + minimale Sperrseite mit Cockpit-Link. PHP-Lint: ok. - game.html respektiert
LOGISTIK_FORCED_LEVELbeimode === 'teacher_started'(URL ?level wird ignoriert). - Assessment-Calls via
LG_API.postAssessment(phase, payload):starteddirekt nach Engine-Initrunningalle 30 s Heartbeat aus RAF-Loop (mit balance, completed, active, ratios, round)completedbeiLEVEL_SUCCESS/LEVEL_FAILED(mit finalBalance, minTarget, success, kennzahlen)- Alle fire-and-forget via bestehende LG_API-Infrastruktur (401 -> session-disabled)
L1-Progression-UI-Polish
- Away-Bonus-Badge auf Auftragskarten:
↗ woandersin Beige, wennc.awayBonus === true(= Origin nicht an Vehicle-Location) - Runden-Anzeige im Header: Level-Badge zeigt jetzt
Level 1 · Runde 3auf L1 (andere Level unveraendert)
Regel R-1 engine-seitig als Soft-Check
- In
loadContent:_validateRuleR1(cfg)loggtconsole.warnmit Formel + benoetigtem Betrag, wenn Level die Regel verletzt. L3 triggert den Warn aktuell (2.500 € < 4.650 €). Nicht blockierend — Lehrkraft kann bewusst ueberschreiben.
Manueller Fahrzeugkauf ab L2
- Engine:
LogistikEngine.buyVehicle(game, mode)+LogistikEngine.VEHICLE_PRICES(TRUCK_SMALL 5k, TRUCK_LARGE 15k, TRAIN 40k). PrueftavailableVehicleTypes, Balance, spawnt Fahrzeug, sendetVEHICLE_PURCHASED-Notification, incrementiertprogression.trucksBought. - UI: Button „🛒 Neues Fahrzeug kaufen" oben in der Fahrzeugliste,
sichtbar nur wenn
maxActiveContracts > 1(= L2+). Klick oeffnet Dialog-Overlay mit 3 Typen: Icon, Name, Kurz-Hint, €/km+€/h, Preis. Nicht-leistbare Fahrzeuge grau + Preis rot. Erfolg → Toast + Re-Render.
Testbar jetzt
- http://localhost/geograsim/App/logistik?level=1 — L1-Progression, Runden-Badge sichtbar, Auto-Buy bei 15k, Away-Bonus-Auftraege ab Runde 2 markiert
- http://localhost/geograsim/App/logistik?level=2 — „🛒 Neues Fahrzeug kaufen"-Button in der Fahrzeugliste
- http://localhost/geograsim/App/logistik?level=3 — R-1-Warn in der Browser-Konsole
Was jetzt auf Atlas/Thomas wartet
- Atlas-Review aller 3 offenen Mails in zentrale (Phase-7b-Fertig, 17:00 Warnton+Trip-Koppeln, 17:30 L3-Balance+R-1)
- Atlas-Meldung wegen
.ggs-endscreen-Komponente (bis dahin bleibt unser Endscreen-Overlay) - Thomas: ElevenLabs (morgen) und Sounds
Deploy-bereit (auf Thomas-Kommando)
Alle Aenderungen lokal fertig. Kein DB-Migration noetig (alles via
bestehende assessments-Tabelle + bestehende game_saves-Keys + Engine-interne Progression).
2026-04-24 ~11:00 — Deploy von Atlas durch (Option B)
Atlas hat den Deploy selbst koordiniert — antwortete auf meine
Anfrage vom Morgen (zentrale/2026-04-24-0900-logistik-deploy-anfrage.md).
Auf Prod live (https://geograsim.at/):
- ✅
pages/logistik.php— mode-check + forcedLevel + easy + Sperrseite - ✅
php/api/logistik-sessions.php,logistik-saves.php,logistik-analytics.php - ✅
sims/logistik/game.html(~149 KB, aktueller Stand) - ✅ DB:
lg_contracts_logexistiert und leer, bereit - ✅ DB:
students.easy_languageadditiv ergänzt (Default 0) - ✅ Module-IDs-Migration sim-XX → klima/heli/fluss/logistik
- ✅ HTTP-200 auf
/logistikund/modul-logistik
Reviews geschlossen:
- Phase 7b Fertig — gelesen, kein Review noetig
- Warnton + Trip-Integration — kommt als Phase 8e separat
- L3-Balance + R-1 — Atlas delegiert an mich:
game_levels.params- Update mache ich selbst in einem Sweep, kein Atlas-Eingriff noetig
Noch bei mir offen (nicht blockierend):
- L3 startBudget 2.500 → 5.000 in
game_levels.paramsvia UPDATE-SQL (Empfehlung A aus meiner 23.04 17:30 Mail) — wartet auf Thomas-OK - Sounds — Thomas kuemmert sich um ElevenLabs
- End-Screen-Umstellung auf
.ggs-endscreen— wartet auf Atlas-Komponenten-Meldung
2026-04-24 ~13:00 — Alle delegierten Schritte umgesetzt
L3-Balance-Fix
- SQL-Migration:
App/Don_t_Deploy/2026-04-24-logistik-l3-balance-fix.sqlsetzt L3params.startBudgetauf 5.000 (war 2.500). - Lokal ausgerollt auf XAMPP-MariaDB. Verifikation OK.
- Wartet auf naechsten Deploy → Atlas (siehe Mail
zentrale/2026-04-24-1300-logistik-l3-migration-und-balance-korridor.md).
Balance-Korridor-Doku + Mechanik
- Neue Doku:
App/sims/logistik/balance-corridor.md - Drei Regeln formal:
- R-1 Runway:
startBudget ≥ 1.5 × Tagesfixkosten— Engine-Warn. - R-2 Winnable: per Level min. 1 Strategie schafft Median-success ueber 5 Seeds.
- R-3 Loseable: noop schlaegt 100% fehl, zusaetzlich strategie- spezifische Anforderungen pro Level.
- R-1 Runway:
- Neuer Button
Balance-Korridor-Check (R-1/R-2/R-3)inheadless-runner.html: faehrt 45 Durchlaeufe (3 Lvl × 3 Strategien × 5 Seeds) und liefert PASS/FAIL pro Regel + Level. Auch greedy als Proxy fuer optimal verwendet (Stub fehlt noch). - Aktuelle Verifikation R-1 mathematisch: L1/L2/L3 alle PASS nach Fix.
Bekannte Luecke (nicht-blockierend)
optimal-Strategie inheadless-runner.jsist noch Stub (wirft). Damit ist L3-Winnability nicht hart-verifiziert. Folgearbeit, sobald nichts dringender ist.
Atlas-Mail raus
zentrale/2026-04-24-1300-logistik-l3-migration-und-balance-korridor.md
mit SQL-Migration zum naechsten Deploy + Korridor-Doku zur Kenntnis.
2026-04-24 ~14:00 — optimal-Strategie implementiert
Die letzte offene Luecke im Balance-Korridor geschlossen.
Was gebaut
headless-runner.js — optimal ist nicht mehr ein Stub, sondern eine
Best-Net-Heuristik:
- Pro Tick alle (contract, vehicle)-Paarungen bewerten:
net = reward × 1.15 − fare − erwartete Verspaetungsstrafemitfare = pickup-km × €/km + pickup-h × €/h + delivery-km × €/km + delivery-h × €/hundexpectedPenalty = rewardBase × latePenaltyRate × max(0, totalH − slackH) - Kapazitaets-Constraint hart (Skip wenn veh.capacity < c.containers)
- Paarungen nach Netto sortiert, oben-nach-unten feuern, pro Iteration jedes Vehicle/Contract max. 1×
- Unprofitable Paarungen (net ≤ 0) werden ausgelassen
~120 Zeilen, UMD-konform (laeuft in Browser + Node). Intermodal noch ausgeklammert (wie greedy).
Korridor-Check jetzt vollstaendig
headless-runner.html→ „Balance-Korridor-Check" faehrt jetzt 60 Durchlaeufe (3 Lvl × 4 Strategien × 5 Seeds)- R-2 ueber
optimalhart verifizierbar (nicht mehr nur greedy-Proxy) - R-3 strenger: zusaetzlich zur noop-Regel wird fuer L2 naive und L3 greedy auf Median-Fail geprueft (Level muss schwerer werden, nicht nur durch Untaetigkeit verlierbar)
Docs aktualisiert
balance-corridor.md§5 + §7: Status auf vollstaendig, Luecke geschlossenheadless-runner.jsHeader-Kommentar: Strategie-Beschreibungen korrekt
Test-URL
http://localhost/geograsim/App/sims/logistik/headless-runner.html
→ 3. Button „Balance-Korridor-Check (R-1/R-2/R-3)" druecken → 60 Runs,
Ergebnis-Tabelle mit PASS/FAIL pro Regel + Level + Detail-Zahlen.
Was jetzt noch offen bleibt
- L3-SQL-Migration wartet auf naechsten Deploy (an Atlas via Mail 13:00)
- ElevenLabs-Sounds (Thomas morgen)
- End-Screen-Umstellung auf
.ggs-endscreen(wartet auf Atlas) - Phase 8e Warnton + Trip-Integration (wartet auf Atlas-Meldung)
2026-04-24 ~16:00 — Phase 8e: L1-Stufen-Progression mit Accept/Decline
Auf Thomas-Wunsch: L1 in 6 Stufen geteilt mit jeweils einer neuen
Entscheidungsdimension pro Stufe. Konzept in diesem Status-Update
knapp, ausfuehrlich in level-progression.md nachtragbar.
Die 6 Stufen (L1-intern, reine Engine+UI-Mechanik, kein DB-Change)
| Stufe | ab Runde | Neu | Mechanik |
|---|---|---|---|
| 1 Fahren lernen | 1 | START druecken | 1 Auftrag direkt OPEN, kein Accept noetig |
| 2 Rueckweg waehlen | 2 | Annehmen/Ablehnen | offers-buffer=1, Standard-Varianten im Pool |
| 3 Zeitdruck | 4 | Express-Varianten | 30 % Chance auf Eilauftrag (halbe Frist, +50 % Reward) |
| 4 Container-Grenze | 6 | Multi-Container + TRUCK_LARGE-Unlock | 25 % Chance auf 2-Container, Kauf-Dialog zeigt TRUCK_LARGE |
| 5 Parallel disponieren | 8 | 2 OPEN gleichzeitig + offers-buffer=2 | volle Pool-Breite, Distanzen bis 1.5× Mult |
| 6 Soft-Ramp L2 | 11 | Events 0 → 0.3, Fernstrecken | eventProbabilityMultiplier=0.3, poolMaxMult=1.7 |
Neue Engine-Funktionen
CONTRACT_STATE.OFFERED+EXPIREDLogistikEngine.acceptOffer(game, contractId)— setzt OFFERED→OPEN, prueft max-OPEN-SlotsLogistikEngine.declineOffer(game, contractId)— entfernt OFFERED_l1Stufe(game)/_l1StufeCfg(game)— Stufen-Aufloesung via round_totalContractSlots(game)— max-OPEN + offers-buffer_maybeRefillOffers(game)— fuellt total-slots mit OFFERED-Angeboten_expireOffers(game)— entfernt abgelaufene OFFERED nach Sim-Zeit_maybeGenerateEvents+buyVehiclebeachten L1-Stufen-Overrides- Offers expirieren nach 30 Sim-Minuten stumm
- Tick ruft
_expireOffers+_maybeRefillOffersjeden Tick
UI-Neu
- OFFERED-Karten: eigenes Beige-Farbthema, Countdown
⏳ Verfällt in MM:SS - Buttons
✓ Annehmen/✕ Ablehnenpro Angebot - Express-Badge
⚡ Eilauftrag+ Multi-Container-Badge×2 - Header-Badge:
Level 1 · Stufe 3 Zeitdruck · R 5 - Kauf-Button erscheint auf L1 ab Stufe 4 (Container-Grenze)
- Kauf-Dialog zeigt TRUCK_LARGE auf L1 Stufe 4+
- RAF-Loop: Sekunden-Trigger fuer Countdown-Update wenn Offers aktiv
Headless-Runner angepasst
naive/greedy/optimalakzeptieren OFFERED automatisch (Stufe 1 hatte keine, jetzt ab Stufe 2)nooplaesst Offers verfallen → L1 fail wie erwartet
Testbar
- http://localhost/geograsim/App/logistik?level=1 — Runde 1: ein Auftrag. Nach Lieferung: 2 Angebote, echte Wahl
- Balance-Korridor-Check (
headless-runner.html): laeuft jetzt ueber die neue L1-Mechanik
Deploy-Relevant
- Keine DB-Aenderung → keine Migration noetig
- Reiner Code-Deploy (engine.js + game.html)
2026-04-24 ~17:00 — Phase 8e Rückbau (L1 zu komplex, zurück zu simpel)
Thomas-Feedback: „das mit dem Stress, Eilauftrag, geht viel zu schnell, keine Reaktionszeit. In Level 1 gibt es keinen Eilauftrag. Aufträge kommen und gehen, sind vielleicht irgendwann auch weg ... aber sonst zu kompliziert." → simpler machen.
Was rausgenommen
- CONTRACT_STATE.OFFERED aus dem L1-Flow (Enum bleibt im Code, aber Generator setzt es nicht mehr). Aufträge erscheinen direkt als OPEN.
- Accept/Decline-Buttons auf den Auftragskarten
- Countdown „⏳ Verfällt in MM:SS"
- Express-Badge
⚡ Eilauftragund Multi-Container-Badge×2 - RAF-Sekunden-Trigger (war nur für Countdown)
- TRUCK_LARGE-Unlock ab L1 Stufe 4 in
buyVehicle+ UI-Kauf-Dialog - Kauf-Button auf L1 generell (Auto-Buy reicht)
Was bleibt (einfaches Modell)
- 5 Stufen (statt 6), jeweils
maxOpen+poolMaxMult+eventMult:- Stufe 1 Erster Auftrag (R1): 1 OPEN
- Stufe 2 Mehrere zur Wahl (R2): 2 OPEN, gleicher Pool
- Stufe 3 Weitere Strecken (R4): 2 OPEN, Pool bis Mult 1.3 (München)
- Stufe 4 Mehr Fahrzeuge (R7): 3 OPEN, Pool bis Mult 1.5
- Stufe 5 Soft-Ramp → L2 (R11): 3 OPEN, Pool 1.7 + Events 0→0.3
- „Kommen und gehen":
_expireOffers(nur auf L1 aktiv) entfernt OPEN-Auftraege die ihre eigenedueTimeueberschritten haben ohne Fahrzeug-Zuweisung. Silent-Remove + kurze Notification. Keine eigene Ablaufzeit, keine gelben Ringe, kein UI-Alarm — die Frist ist die natuerliche Grenze. - Auto-Buy TRUCK_SMALL bei Balance ≥ 15.000 €: unverändert
- Pool-Staffelung nach Distanz (Stufen-poolMaxMult): unverändert
- Away-Bonus-Badge auf Auftragskarten: bleibt (ist subtil, nicht stressig)
- Runden-/Stufen-Anzeige im Header: aktualisiert auf neue Stufen-Namen
Engine-Seite
L1_STUFEN[]hat jetzt nur{n, name, minRound, maxOpen, poolMaxMult, eventMult}_effectiveMaxContracts(game)nimmtstufe.maxOpendirekt_totalContractSlots = _effectiveMaxContracts(kein Buffer-Konzept mehr)_generateL1ContractFromPool: immer OPEN, 1 Container, nicht Express_expireOffers→ silent-removes OPEN mit abgelaufener dueTime (nur L1)
Headless-Runner
acceptOffer-Aufrufe in naive/greedy/optimal bleiben stehen (try/catch — no-op wenn keine OFFERED-Angebote da sind)- L1 sollte jetzt wieder mit noop=fail, naive=success laufen
Testbar
http://localhost/geograsim/App/logistik?level=1 — Runde 1: ein Auftrag (wie altbewährt). Nach Lieferung: zwei Aufträge parallel, ohne Accept-Klick, jeder mit eigener dueTime. Wer ignoriert wird, verschwindet irgendwann still. Kein Stress, keine Eilaufträge, keine Countdown-Alarme.
Nicht-Deploy-blockierend
Keine DB-Änderung, reiner Code-Deploy.
2026-04-24 ~18:00 — Phase 8e Ausbau: Variety, History, Verfahren-Event
Thomas-Feedback: „Ab der zweiten Fahrt sollte es 3-4 Optionen geben. Manchmal attraktiver mit längerer Anfahrt, manchmal finanziell gut aber zeitlich knapp — muss an den Zahlen erkennbar sein. Fahrt-Protokoll als Pill." Plus Zusatzaufgabe: „Fahrer:in hat sich verfahren"-Event.
Mehr Optionen ab Runde 2
L1_STUFEN.maxOpen erhoeht:
- Stufe 1 (R1): 1 Auftrag
- Stufe 2 (R2+): 3 Auftraege parallel (war 2)
- Stufe 3+ (R4+): 4 Auftraege parallel
poolMaxMultauch schneller erweitert: Stufe 2 schon auf 1.3 (München)
Profile-Variance im Generator
Jedes Angebot bekommt ein Profil gewuerfelt (Stufe 1 immer standard):
| Profil | Gewicht | Reward-Mult | Frist-Mult | Pool-Filter |
|---|---|---|---|---|
| standard | 50 % | 1.0 | 1.0 | — |
| tight (Frist knapp) | 20 % | 1.3 | 0.6 | — |
| far (Weite Fahrt) | 15 % | 1.0 | 1.0 | mult ≥ 1.5 |
| easy (Kurz) | 15 % | 0.85 | 1.3 | mult ≤ 1.0 |
Profil-Name wird auf contract.profile gespeichert, UI-Badge rendert:
- ⚡ knappe Frist (orange)
- 🌍 weite Fahrt (blau)
- 🌿 kurz (grün)
Zeit-Reserve-Berechnung sichtbar
Beim Klick auf Fahrzeug (Lademodus) rechnet jede Auftragskarte jetzt:
Fahrkosten ≈ X €+Marge ± Y €(wie bisher)- NEU:
⏰ Z.Z h Reservein Grün/Orange/Rot:- ≥ 3 h grün (entspannt)
- 1–3 h orange (knapp)
- 0–1 h rot (kritisch)
- < 0 h rot „Frist NICHT zu schaffen"
Dadurch erkennt der Spieler an den Zahlen: ⚡ knappe Frist-Auftraege
mit hohem Reward sind nur machbar wenn die Zeit-Reserve es zulaesst.
Fahrt-Historie als Pills
Neuer UI-Strip zwischen Status-Leiste und Didaktikfenster:
📜 Historie: Fahrt 1 +523 € | Fahrt 2 −120 € | Fahrt 3 +890 €- Grüne/rote Pills je nach Netto-Vorzeichen
- Klick auf Pill → Detail-Modal mit Strecke, Container, Dauer, Verspätung, Netto
Strip erscheint nur wenn ≥ 1 Lieferung abgeschlossen. Horizontal scrollbar bei vielen Pills.
Zusatzaufgabe: Verfahren-Ereignis
- Engine-Trigger: Mit 6 % / Sim-Stunde pro Fahrzeug im
*_driveab L1 Stufe 2 wuerfelt ein Verfahren-Event. Bei Treffer:vehicle.verfahrenPending = truevehicle.verfahrenTargetLocationId= aktueller Trip-Zielortvehicle.verfahrenDriverLabel= „Fahrerin Anna" oder „Fahrer Tom" (alternierend uebergame.progression.verfahrenCount)- Fahrzeug pausiert in
_updateVehicles(keine Bewegung, keine Zeit-Verbrauch) - Notification
DRIVER_LOSTwird gefeuert
- UI-Banner am oberen Map-Rand:
🤷 Fahrerin Anna hat sich verfahren! Bring sie nach Salzburg — klick den Ort auf der Karte. - Map-Klick-Handler pro Stadt-Marker:
- Wenn ein Fahrzeug
verfahrenPendinghat und der geklickte Ort das Ziel ist →LogistikEngine.resolveDriverLost(game, vehicleId, locationId)→ Fahrt geht weiter - Falscher Ort → Toast-Hinweis, Event bleibt aktiv
- Wenn ein Fahrzeug
- Didaktik: uebt Kartenorientierung; Zielstadt muss identifiziert werden
Minigame-Buttons korrigiert
- 🎮 Einparken: jetzt auf allen Levels sichtbar (war fälschlich an
minigamesEnabledgebunden, dadurch L1 leer) - 🚆 Rangieren: nur sichtbar wenn TRAIN im Fuhrpark (L1 hat keinen → Button aus)
Testbar
http://localhost/geograsim/App/logistik?level=1:
- Runde 1: 1 Auftrag (Tutorial)
- Runde 2+: 3-4 Optionen mit unterschiedlichen Profilen, durchgemischt
- Zeit-Reserve erscheint beim Klick auf Fahrzeug
- Trip-Pills unten nach jeder Lieferung
- Gelegentlich Verfahren-Event → Stadt auf Karte zeigen
- 🎮 LKW-Einparken-Button sichtbar
Reiner Code-Deploy, keine DB-Aenderung
2026-04-24 ~19:00 — End-Screen transparent + L1 längere Spielzeit + Favicon
End-Screen-Zahlen klarer
Alter End-Screen zeigte nur „Ø Netto/Auftrag" und „Endbilanz". Das war
irreführend, weil in Multi-Contract-Touren Fahrkosten im Tick
abgezogen werden, aber NICHT in contract.finalBalance — Summe der
avgNet × Anzahl stimmte nicht mit Endbilanz überein. Thomas sah:
3 × 1247 = 3741 vs. Endbilanz +2547, konnte es nicht nachvollziehen.
Neu im End-Screen — komplette Konto-Rechnung sichtbar:
- Startbudget
- Erlöse (Basis + Bonus) +X €
- Strafen −X €
- Fahrkosten −X €
- Laufende Kosten −X €
- Zuwachs (Konto) ±X €
- Min-Ziel
Jetzt kann der Spieler selbst ausrechnen, wo das Geld hin ist. Die
Zahlen-Quellen sind dieselben wie vorher (game.analytics), nur die
Zeilen transparenter gruppiert.
L1 timeLimitHours 24 → 72
Thomas-Feedback: „das Spiel sollte deutlich länger gehen". L1-Tutorial war bei 4×/8× nur 3-6 Echt-Minuten lang, fühlte sich gehetzt an.
SQL-Migration: App/Don_t_Deploy/2026-04-24-logistik-l1-timelimit-72h.sql
setzt game_levels.params.timeLimitHours von 24 auf 72 (= 9 Echt-Min
bei 8×, 18 Echt-Min bei 4×). Andere Parameter unverändert: Min-Ziel
3.000 €, Events aus, BLINK_EXACT-Hilfe.
Lokal ausgerollt auf XAMPP. Aktueller DB-Stand:
L1: timeLimitHours=72 (war 24)
L2: timeLimitHours=48 (unverändert)
L3: timeLimitHours=72 (unverändert, startBudget=5000 seit letztem Fix)
Favicon verdrahtet
game.html hatte keine <link rel="icon">-Tags → Browser-Tab zeigte
Generic-Icon. Jetzt analog zu heli/lehrplan/glossar:
game.htmlreferenziert../../favicon.svg+../../favicon-96x96.pnglogistik.php-Wrapper biegt beide Pfade auf absoluteBASE_PATH-URLs um (im bestehendenstrtr-Block)
Offene Deploy-Items für Atlas
Sammel-Liste der lokalen DB-Änderungen, die noch auf Prod müssen:
2026-04-24-logistik-l3-balance-fix.sql— startBudget 2500 → 50002026-04-24-logistik-l1-timelimit-72h.sql— L1 timeLimit 24 → 72- Seed-Einträge
class_modulesfür logistik='free' pro Klasse (lokal nur)
Diese drei Migrations sind reine game_levels.params / class_modules
Updates, keine Schema-Änderungen.
2026-04-24 ~19:30 — Auto-Boost Fahrtzeit
Thomas-Wunsch: „In Phasen, in denen nur Fahrtzeit erwartet wird, die Timescale automatisch auf 8× springen und dann automatisch zurück."
Mechanik
- Gespeicherte Player-Wahl (
playerSpeed) vs. aktuelle sim-Geschwindigkeit - Jeden Frame
updateAutoBoost():- Condition:
allBusy = alle Fahrzeuge haben tripPhase && keinen verfahrenPending shouldBoost = allBusy && kein Verfahren-Event offen- Wenn true +
!autoBoostActive→ setTimeScale(8), Flag setzen - Wenn false +
autoBoostActive→ setTimeScale(playerSpeed), Flag loeschen
- Condition:
- Klick auf einen Speed-Button:
playerSpeedupdaten, AutoBoost deaktivieren (manueller Override hat Vorrang) - Pause (0×): Auto-Boost greift nicht
UI
- Spieler-Button bleibt aktiv (visueller Anker)
- Neuer Badge
⚡ Auto 8×rechts neben den Speed-Buttons pulsiert sanft gelb, wenn Auto-Boost aktiv - Tooltip: „Alle Fahrzeuge unterwegs — Sim läuft automatisch auf 8×. Pressen einer Taste übernimmt wieder die Kontrolle."
Auto-Release in diesen Fällen
- Ein Fahrzeug wird IDLE (Lieferung fertig) → Spieler könnte neuen Trip starten
- Verfahren-Event triggert → Spieler muss Karte klicken
- Spieler klickt selbst eine Speed-Taste
Testbar
http://localhost/geograsim/App/logistik?level=1:
- Assign Auftrag zu Lok → Fahrt startet → sobald sie rollt: ⚡ Auto 8× Badge pulsiert gelb, Sim-Zeit rennt
- Lieferung fertig → Fahrzeug IDLE → Badge verschwindet, Zurück auf Spieler-Speed (normalerweise 1×)
2026-04-24 ~20:00 — Road-Dijkstra + Verfahren-Penalty + Auto-Boost-Override
Straßennetz-Routing für LKWs
Thomas: „LKW fährt Luftlinie Salzburg→Berlin, unrealistisch."
- Neuer Seed
App/assets/data/lg-roadnet.json: 11 Knoten (Stadt-Hubs) + 13 Edges mit echten Autobahn-Distanzen (A1/A7/A8/A9 etc) logistik.phpinjiziert Roadnet inLOGISTIK_SEEDS.roadnetengine.jsloadContent: nimmt Roadnet inworldState.roadnetaufcalculateRoutefür TRUCK_SMALL/TRUCK_LARGE: erst Dijkstra auf Roadnet, Geometry = Polyline durch die Dijkstra-Knoten, Segments pro Kante mitrouteCode(A8, A9 etc). Fallback routesOsm/Luftlinie für Locations ausserhalb des Roadnet-Graphs.- Salzburg→Berlin fährt jetzt salzburg→muenchen→berlin (150+580=730km) statt Luftlinie (590km).
Vertagte Follow-Up: Höhere „Auflösung" der Polylines
Thomas: aktuell sind Polyline-Segmente zwischen Stadt-Knoten gerade
Linien. Echte Autobahnen haben Kurven. Option C aus meinem Feedback:
hand-gepflegte Polylines pro Road-Kante in lg-routes-osm.json
(13 Paare × 5-10 Stützpunkte ≈ 1.5 h Arbeit). In die To-Do-Liste
aufgenommen, niedrige Prio.
Verfahren-Ereignis: Zeit-Strafe + Capital-Only
Thomas-Wunsch: Stufe A (Zeit-Strafe statt sichtbarem Detour), nur Hauptstädte zaehlen (sonst iPad-Fat-Finger-Problem).
- Engine
resolveDriverLost(game, vehicleId, clickedLocationId, locationType)unterscheidet jetzt 3 Fälle:locationType !== 'CAPITAL'→ignored:true, kein Strafe, UI zeigt „Nur Hauptstädte zählen"- Falsche Hauptstadt →
wrong:true, wastedHours:1.5, akkumuliert invehicle.verfahrenPenaltyHours, Event bleibt offen - Richtige Hauptstadt → löst Event auf, rechnet akkumulierte Strafe
in Reduktion von
segmentProgressum (max 90 % zurück) → Restfahrt dauert entsprechend laenger, late-fee-Risiko steigt
- UI-Marker-Klick reicht
loc.typemit, Toasts differenziert nach Fall - Konstante
VERFAHREN_PENALTY_H = 1.5in engine.js
TimeScale-Override bei Verfahren
Thomas: „Beim Verfahren TimeScale 1."
effectiveTimeScale()mit Prioritaet: Pause → Verfahren 1× → AutoBoost 8× → playerSpeed- Wenn Verfahren-Event triggert: egal ob vorher Player auf 4× oder AutoBoost 8× war, Sim springt sofort auf 1×
- Nach Resolution: zurueck zur richtigen Stufe
- AutoBoost-Badge wird waehrend Verfahren ausgeblendet
2026-04-24 ~20:30 — QoL: Auto-Select + Auto-Swap + Layer-Control raus
Auto-Select beim Lademodus
Thomas: „Das oberste freie Fahrzeug ist automatisch schon markiert und offen. Sobald es steht."
- In
renderVehicles(): wenn keinloadingVehicleId→ setze auf erstes IDLE-Fahrzeug ohne tripPhase. Auch beim Game-Start. - Wenn das aktuell gewählte IDLE-Fahrzeug losfährt (tripPhase wird gesetzt) → automatisch auf nächstes IDLE umschalten
- Resultat: Spieler klickt nur noch Aufträge, das Fahrzeug ist vorausgewählt
Auto-Swap im Laderaum
Thomas: „Wenn ein Auftrag bereits zugewiesen ist und ein anderer angeklickt wird, der nicht mehr Platz hat, fliegt der Auftrag, der bereits im LKW drin ist, wieder raus."
- In Auftragskarten-Klick-Handler:
- Wenn Auftrag bereits im Fahrzeug geladen: Toggle → entladen
- Wenn
loadContractwegen vollem Laderaum failt: ältesten geladenen AuftragunloadContract, dann neu versuchen - Toast-Message: „🔄 X geladen (Y ausgetauscht)" statt Fehler
- Spieler kann durch Aufträge schnell durchblättern
Layer-Control-Widget entfernt
Thomas: „Die Auswahl zur Ansicht rechts oben (Hauptstädte, Städte, Häfen, Terminals und Bahnnetz) kannst du entfernen. Wir zeigen einfach immer alles an."
L.control.layers(...)entfernt aus der Karten-Initialisierung- Alle Layer werden unbedingt dem Map hinzugefügt (capitals, cities,
ports, terminals); Bahnnetz nur wenn
railEnabledim Level-Config - Die Karte hat jetzt keine Widget rechts oben mehr
2026-04-24 21:30 — Bonus-Pills + Gratulations-Modal + Städte Tier 1 + Atlas-Mail
Atlas-Mail raus: Info-Cards mit Bildern (Heli-Pattern)
_inbox/zentrale/2026-04-24-2100-logistik-infocards-heli-pattern.md- 5 konkrete Fragen: Heli-Card-Komponente, Bild-Pfad/Lizenz, Granularität (pro Auftrag vs. pro Zielort), AI-Pipeline, Design-System-Wiederverwendbarkeit
- Thomas-Wunsch: pro Start eine Info-Card mit Bild der Zielstadt
- Warte auf Atlas-Antwort; baue derweil andere Tasks
Gratulations-Meldungsfenster
Thomas: „einen zweiten LKW bekommen. Dies wurde aber nicht angekündigt. In einem solchen Fall bitte kurzes Meldungsfenster. Gratulation..."
- Neue Komponente
.lg-announce-overlay+.lg-announce-modalin game.html (CSS + DOM) announce(icon, title, text, sub)— Scale-in-Animation, 4 Sek auto-close, Click schließt sofort- VEHICLE_PURCHASED-Notification wird via
drainNotifications()auf das Modal umgeleitet (statt Toast) checkStufeChange()vergleicht_l1StufemitlastAnnouncedStufe, feuert Modal bei Stufen-Wechsel mit Stufen-Parametern (maxOpen/poolMaxMult/eventMult)
Bonus-Pills UI komplett
Thomas: „rechts oben Pills setzen, klickbar für Info, automatisch benutzt. Stack-Limit gute Idee. Bonusskala passt."
- Container
#bonusPillsoben rechts über der Karte (absolute positioniert,pointer-events: auto) renderBonusPills()zeichnet die FIFO-Queue ausgame.pendingBonuses(cap 5); jede Pill mit ⏱ Icon + Minutenwert + Quellen-TooltipshowBonusPopover(idx)— Click zeigt kurzes Erklär-Popover („Bonus aus Rangier-Minispiel — wird beim nächsten Laden angewendet")flyBonusToVehicle(vehicle)— Consumption-Animation: Pill fliegt zum Fahrzeug-Marker, skaliert auf 0, dannpendingBonuses.shift()- Minispiel-Hook in
mgApplyResult: bei SuccessLogistikEngine.pushLoadBonusmit 45/20/5 min je nach Zeit (<15s/<30s/<60s) - Engine hat
_consumeNextLoadBonus(game, vehicle)an 4 Phase-Transitions (pickup/loading/unloading/dropoff)
Layer-Fix: Ports + Terminals wirklich sichtbar
Fehler nach Layer-Control-Removal: visibleLevel-Filter im marker
forEach blockte Ports/Terminals (nur ab L3 sichtbar).
- Filter entfernt — alle Locations immer gerendert
bindPopupzeigt jetzt Name + Typ-Label (Hauptstadt/Stadt/Hafen/ Terminal) +didacticInfoals kleinen Absatz- Popup-CSS
.lg-loc-popupmit typeLabel-Subtitle
Städte-Erweiterung Tier 1 (Hauptstädte)
Thomas: „Mache einen Entwurf und gib vor, wie viele Städte in Europa relevant wären."
App/assets/data/lg-locations.jsonvon 13 auf 27 Einträge erweitert (alle bestehenden Einträge behalten IDs/Koordinaten)- +14 Hauptstädte: Rom, London, Brüssel, Amsterdam, Prag, Budapest, Athen, Stockholm, Oslo, Helsinki, Dublin, Lissabon, Bern
- Jeder Eintrag hat
didacticInfo— 1 Satz mit logistik-relevantem Geo-Fakt (Verkehrsknoten, Hafen-Kapazität, EU-Status etc.) regionIdkonsistent gesetzt (benelux, scandinavia, iberia, western_europe, southern_europe, central_europe)- Offen: Tier 2 (~50 Großstädte) + Tier 3 (~25 Häfen/Terminals) — Konzept steht, Umsetzung vertagt
Auto-Timescale-Badge dynamisch
Thomas: „bei der Auto Timescale steht immer Auto 8× .. die Zahl sollte sich aber ändern, wenn nicht reine Fahrt aktiv ist."
- Badge-Text wird jetzt pro Frame aus
effectiveTimeScale()gesetzt ⚡ Auto 8×bei reiner Fahrt,⚡ Auto 1×bei Verfahren-Event (wenn playerSpeed != 1)- Badge hidden wenn Auto-Logik nicht override-t (playerSpeed==target)
updateAutoBoost()resettet Badge auch bei non-RUNNING States (MINIGAME/PAUSED/LEVEL_SUCCESS), bisher blieb es stale sichtbar
Offene Punkte
- Atlas-Antwort zu Info-Cards (5 Fragen vom 21:00)
- Städte Tier 2/3 (Konzept steht, ausbauen)
- Uhr mit Stunden/Minutenzeiger + Tag/Nacht in Karten-Ecke
- Pausepflicht LKW bei Langstrecken in höheren Levels
- Sounds via ElevenLabs (Thomas macht morgen)
- Polyline-Auflösung Option C (hand-gepflegt pro road-edge)