CLAUDE.md: Planer-Dokumentation auf aktuellen Stand gebracht

Datenmodell, Roadmap, Gantt-Entscheidungen, Äquivalente-Ort und
Recast-Format aktualisiert; veraltete Punkte entfernt.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
xziino 2026-05-22 16:33:39 +02:00
parent 4801148a8c
commit 58745fec65

108
CLAUDE.md
View File

@ -239,19 +239,22 @@ Raid-Cooldown-Planer: Welche Mitigation-Ability wird für welche Mechanik einges
"name": "M8S Prog Week 1", "name": "M8S Prog Week 1",
"createdAt": 1234567890, "createdAt": 1234567890,
"updatedAt": 1234567890, "updatedAt": 1234567890,
"source": { "reportCode": "abc123", "fightId": 6 }, "source": { "reportCode": "abc123", "fightId": 6, "fightName": "Howling Blade", "fightStart": 0, "fightEnd": 420000, "language": "en" },
"mitigationNames": { "Reprisal": "Vergeltung" },
"folderId": null,
"jobComposition": ["PLD", "WAR", "WHM", "SCH", "MNK", "DRG", "BRD", "SMN"], "jobComposition": ["PLD", "WAR", "WHM", "SCH", "MNK", "DRG", "BRD", "SMN"],
"mechanics": [ "mechanics": [
{ {
"id": "uuid", "id": "uuid",
"name": "Fourth-Wall Fusion", "name": "Fourth-Wall Fusion",
"abilityId": 12345,
"timestamp": 83000, "timestamp": 83000,
"phase": "Phase 1", "phase": "Phase 1",
"unmitigatedDamage": 280000, "unmitigatedDamage": 280000,
"notes": "", "notes": "",
"assignments": [ "assignments": [
{ "ability": "Reprisal", "job": "PLD" }, { "ability": "Reprisal", "abilityName": "Vergeltung", "job": "PLD", "buffType": "debuff" },
{ "ability": "Shield Samba", "job": "BRD" } { "ability": "Shield Samba", "abilityName": "Schildsamba", "job": "BRD", "buffType": "buff" }
] ]
} }
] ]
@ -259,6 +262,8 @@ Raid-Cooldown-Planer: Welche Mitigation-Ability wird für welche Mechanik einges
``` ```
Mehrere Pläne gespeichert in `localStorage` unter `ff14-planner-plans` als Array. Mehrere Pläne gespeichert in `localStorage` unter `ff14-planner-plans` als Array.
Ordner gespeichert unter `ff14-planner-folders`. Pläne referenzieren Ordner per `folderId`.
Aktiver Plan per `ff14-planner-active-plan` (ID) — wird beim Tab-Öffnen wiederhergestellt.
### Primärer Import-Flow: Export aus dem Analyse-Tab ### Primärer Import-Flow: Export aus dem Analyse-Tab
Der Haupteinstieg ist der Analyse-Tab — der Nutzer hat die Daten bereits geladen und sieht die Timeline. Der Haupteinstieg ist der Analyse-Tab — der Nutzer hat die Daten bereits geladen und sieht die Timeline.
@ -271,30 +276,61 @@ Der Haupteinstieg ist der Analyse-Tab — der Nutzer hat die Daten bereits gelad
4. AoE-Events werden zu Mechaniken; Phase-Information aus `phaseTransitions` wird mitübernommen 4. AoE-Events werden zu Mechaniken; Phase-Information aus `phaseTransitions` wird mitübernommen
5. Weiterarbeiten im Planer-Tab 5. Weiterarbeiten im Planer-Tab
**Merge-Logik:** Mechaniken gelten als identisch wenn `abilityName` gleich und `|timestamp_a - timestamp_b| < 5000ms`. Nur neue Mechaniken werden hinzugefügt, bestehende Assignments bleiben erhalten. Neue Mechaniken werden timestamp-sortiert eingefügt. **Merge-Logik:** Mechaniken gelten als identisch wenn `|timestamp_a - timestamp_b| < 1500ms`. Nur neue Mechaniken werden hinzugefügt, bestehende Assignments bleiben erhalten. Neue Mechaniken werden timestamp-sortiert eingefügt.
**Warum Merge statt Überschreiben:** Progress-Szenario — erster Import enthält Phase 1, späterer Import fügt Phase 2 hinzu ohne Phase-1-Planung zu verlieren. **Warum Merge statt Überschreiben:** Progress-Szenario — erster Import enthält Phase 1, späterer Import fügt Phase 2 hinzu ohne Phase-1-Planung zu verlieren.
**Sprachlokalisierung:** `api/analysis.php` gibt `mitigation_names` (key → lokalisierter Name) zurück. Plan speichert diese in `mitigationNames`. `refreshPlanLanguage()` in `planner.js` aktualisiert Namen wenn Sprache wechselt (Event `ff14-language-change`). Anzeigename via `assignmentAbilityName(assignment, plan)`.
### Implementierungs-Reihenfolge ### Implementierungs-Reihenfolge
| Schritt | Feature | Beschreibung | | Schritt | Status | Feature |
|---|---|---| |---|---|---|
| 1 | **Datenfundament** | Plan-Datenmodell + localStorage CRUD (create, read, update, delete, copy) | | 1 | ✅ | **Datenfundament** — Plan-Datenmodell + localStorage CRUD |
| 2 | **Tab-Grundgerüst** | Leere Tab-Hülle wie Analyse-Tab; Plan-Liste; Mechanik-Timeline (read-only) | | 2 | ✅ | **Tab-Grundgerüst** — Plan-Liste, Ordner, Mechanik-Timeline |
| 3 | **Import aus Analyse-Tab** | Export-Button + Dialog (s. oben); `window.plannerTab.importFromAnalysis()` | | 3 | ✅ | **Import aus Analyse-Tab** — Export-Button + Dialog + Merge |
| 4 | **Jobaufstellung** | 8 Slots mit Job-Dropdown; bestimmt verfügbare Abilities in Schritt 5 | | 4 | ✅ | **Jobaufstellung** — 8 Slots mit Job-Dropdown + Rollenfärbung |
| 5 | **Ability-Zuweisung** | Pro Mechanik Abilities per Modal-Picker hinzufügen/entfernen | | 5 | ✅ | **Ability-Zuweisung** — Modal-Picker + Rechtsklick-Remove + Äquivalenz-Hints |
| 6 | **Recast-Konflikt** | `data/recast-times.json`; rote Warnung wenn CD zwischen zwei Mechaniken noch läuft | | 6 | 🔜 | **Gantt-Chart** — Recast-Konflikte + DR%-Anzeige (s. unten) |
| 7 | **DR-Simulation** | `simuliert = unmitigated × ∏(1 dr_i)`; grün/rot ob Spieler laut Simulation überlebt | | 7 | 🔜 | **Analyse-Overlay** — geplante vs. tatsächlich genutzte CDs |
| 8 | **Job-Äquivalente** | `data/ability-equivalents.json`; auto-substituieren beim Job-Wechsel |
| 9 | **Analyse-Overlay** | Vergleich geplanter vs. tatsächlich genutzter CDs im Analyse-Tab |
Schritte 13 = nutzbarer MVP. Schritte 46 = praktisch einsetzbar. 79 = Power-Features. ### Gantt-Chart — Design-Entscheidungen (Schritt 6)
**Konzept:** Ergänzende Ansicht zur Mechaniken-Übersicht, nicht Ersatz. Umschaltbar per Toggle/Tab.
**Layout:**
- X-Achse: Kampfzeit (0 bis Kampfende aus `source.fightEnd - source.fightStart`)
- Linke Spalte: Ability-Icons (eine Zeile pro eingesetzter Ability im Plan) — Zeilengranularität TBD
- Vertikale Linien: Mechaniken-Timestamps
- Farbige Balken: Ability aktiv (Dauer) + Cooldown-Bereich danach (gedimmt)
- Konflikte: wenn ein Balken eine Mechaniken-Linie überlappt = visuell hervorgehoben
**Drag & Drop:**
- Ability-Icons aus Palette auf Timeline ziehen → Icon am Startpunkt, Balken zeigt Dauer
- Freies Ziehen ohne Snapping — Timestamp wird aus X-Position berechnet
- Bestehende Balken sind ebenfalls verschiebbar
**Update-Button:**
- Gleicht Gantt-Positionen mit Mechaniken ab
- Matching-Logik: TBD (Overlap oder nächste Mechanik) — noch zu klären
- Aktualisiert Plan-Assignments entsprechend
**DR-Simulation:**
- Pro Mechanik: `simulierter Schaden = unmitigiert × ∏(1 dr_i)` für alle zugewiesenen Buffs/Debuffs
- Wird in der **Mechaniken-Übersicht** unter dem unmitigierten Schadenswert angezeigt
- Schilde werden **nicht** simuliert (Schildwerte nicht verlässlich aus Log ableitbar)
- Kein Pass/Fail-Urteil — nur der errechnete Zahlenwert, User entscheidet selbst
**Recast-Daten:** `data/recast-times.json` — noch zu befüllen. Enthält Cooldown-Dauer (s) und Aktiv-Dauer (s) pro Ability:
```json
{ "Reprisal": { "recast": 60, "duration": 10 }, "Feint": { "recast": 90, "duration": 10 } }
```
### UI-Paradigma ### UI-Paradigma
- Visuell dem Analyse-Tab ähneln (Cards, gleiche CSS-Variablen, einheitliches Look & Feel) - Visuell dem Analyse-Tab ähneln (Cards, gleiche CSS-Variablen, einheitliches Look & Feel)
- Mechaniken als vertikale Timeline-Cards - Mechaniken als vertikale Timeline-Cards — primäre Bearbeitungsfläche bleibt erhalten
- Ability-Picker als **Modal** (kein Inline-Dropdown) - Ability-Picker als **Modal** (kein Inline-Dropdown)
- Gantt als zusätzliche Ansicht für den Planer (derjenige der die CDs koordiniert)
- Nicht für mobile Geräte ausgelegt - Nicht für mobile Geräte ausgelegt
### Spell-Verfügbarkeit nach Job ### Spell-Verfügbarkeit nach Job
@ -324,31 +360,39 @@ Jobaufstellung → verfügbare Abilities (Subset von `MITIGATION_ABILITIES`):
| RDM | Addle, Magick Barrier | | RDM | Addle, Magick Barrier |
| PCT | Addle, Tempera Coat, Tempera Grassa | | PCT | Addle, Tempera Coat, Tempera Grassa |
### Job-Äquivalente (`data/ability-equivalents.json`) ### Job-Äquivalente (in `planner.js` als `ABILITY_EQUIVALENTS`)
Abilities die funktional gleich sind aber unterschiedliche Namen haben — relevant beim Job-Wechsel im Slot: Abilities die funktional gleich sind aber unterschiedliche Namen haben — zeigt Hinweis bei fehlendem Job.
Kein automatischer Austausch — nur Hinweis in rot/grün unter dem ausgegrauten Badge.
| Gruppe | Abilities | | Gruppe | Abilities |
|---|---| |---|---|
| 15% Party-Mitigation | Troubadour, Tactician, Shield Samba | | 15% Party-Mitigation | Troubadour, Tactician, Shield Samba |
| 10% Ground-Barrier | Sacred Soil, Kerachole | | 10% Ground-Barrier | Sacred Soil, Kerachole |
Reprisal, Feint und Addle sind identische Ability-Namen über Jobs hinweg — kein Mapping nötig, die gleiche Ability bleibt einfach bestehen. Reprisal, Feint und Addle sind identische Ability-Namen über Jobs hinweg — kein Mapping nötig.
**Verhalten beim Job-Wechsel:** Assignment wird auto-substituiert wenn Äquivalent für neuen Job existiert (mit Hinweis "automatisch gemappt"). Kein Äquivalent → Assignment ausgegraut (nicht gelöscht, Nutzer entscheidet). ### `extraAbilityGameID` in MITIGATION_ABILITIES (geplant)
Jeder Eintrag in `MITIGATION_ABILITIES` soll ein `actionId`-Feld bekommen — die echte Action-Row-ID aus FFLogs (`applybuff`-Event → `extraAbilityGameID`). Diese ID entspricht direkt der XIVAPI Action-Sheet-Row-ID und ermöglicht automatischen Icon-Lookup:
- 5-stellige IDs: führende 0 ergänzen falls XIVAPI 6 Stellen erwartet
- Lookup: `https://v2.xivapi.com/api/sheet/Action/{actionId}?fields=Name,Icon`
- Ermöglicht künftig automatisches Icon-Fetching statt manueller `MITIG_ICONS`-Pflege
### Recast-Zeiten (`data/recast-times.json`) ### Recast-Zeiten (`data/recast-times.json`)
Wird für Konflikt-Erkennung benötigt (Schritt 6). Vollständige Liste wird beim Implementieren vervollständigt, Beispiele: Format: `{ "Ability": { "recast": 60, "duration": 10 } }` — noch zu befüllen.
- Reprisal: 60s Bekannte Werte (Beispiele):
- Feint / Addle: 90s - Reprisal: recast 60s, duration 10s
- Dark Missionary / Heart of Light: 90s - Feint / Addle: recast 90s, duration 10s
- Troubadour / Tactician / Shield Samba: 120s - Dark Missionary / Heart of Light: recast 90s, duration 15s
- Temperance: 120s - Troubadour / Tactician / Shield Samba: recast 120s, duration 15s
- Temperance: recast 120s, duration 20s
- Sacred Soil / Kerachole: recast 30s, duration 15s
### Technische Entscheidungen ### Technische Entscheidungen
- **Persistenz:** `localStorage` unter `ff14-planner-plans` — kein Backend nötig - **Persistenz:** `localStorage` — kein Backend nötig
- **IDs:** `crypto.randomUUID()` für Plan- und Mechanik-IDs - **IDs:** `crypto.randomUUID()` für Plan-, Mechanik- und Ordner-IDs
- **Eindeutige Namen:** `uniquePlanName()` verhindert Duplikate beim Erstellen und Importieren
- **Keine Spielernamen:** Assignments sind Job-basiert (`{ ability, job }`), damit Pläne übertragbar sind - **Keine Spielernamen:** Assignments sind Job-basiert (`{ ability, job }`), damit Pläne übertragbar sind
- **Kein Ability-Stacking:** FFXIV erlaubt keine doppelte Anwendung derselben Ability — jede Ability kommt pro Mechanik maximal einmal vor, doppelte Instanzen desselben Jobs im Static sind daher kein Sonderfall - **Kein Ability-Stacking:** FFXIV erlaubt keine doppelte Anwendung derselben Ability pro Mechanik
- **Analyse-Overlay (Schritt 9):** Job aus tatsächlichem Pull → lookup welche Ability dieser Job im Plan hatte → Soll/Ist-Vergleich (kein Spielername-Matching nötig) - **Shield-Attribution:** Nicht simulierbar — `absorbed` ist Gesamtwert ohne Aufschlüsselung. Bewusst weggelassen.
- **Shield-Attribution:** Aktuell nicht lösbar — `absorbed` im `damage`-Event ist ein Gesamtwert ohne Aufschlüsselung per Shield. Zu untersuchen: ob `calculatedheal`-Events die Shield-Kapazität beim Auftragen mitliefern. Vorerst zurückgestellt. - **DR-Simulation:** Nur Buffs/Debuffs mit bekanntem `dr`-Wert aus `MITIGATION_ABILITIES`. Ergebnis als Zahlenwert, kein Pass/Fail.
- **Plan kopieren:** Duplicate-Funktion für Plan-Varianten ("Week 3 v2") ohne Original zu verlieren - **fight.php:** Immer englischer Endpoint (`www.fflogs.com`) für stabile Fight-Namen unabhängig von Spracheinstellung