diff --git a/docs/superpowers/specs/2026-09-13-minimap-design.md b/docs/superpowers/specs/2026-09-13-minimap-design.md index 330e51f..13cd1c8 100644 --- a/docs/superpowers/specs/2026-09-13-minimap-design.md +++ b/docs/superpowers/specs/2026-09-13-minimap-design.md @@ -17,6 +17,7 @@ Eine große Kartenansicht des gesamten Vice-City-Ausschnitts, die sich über dem | Kartenbild | Vorab erzeugt, 1 Pixel je Meter. | | Welt während offener Karte | Läuft weiter, keine Pause. | | Klick auf Gebäude oder Wasser | Landung auf dem nächsten begehbaren Punkt im Umkreis von 20 m, sonst Hinweis und kein Sprung. | +| Chunks | Raster auf der Karte sichtbar, jeder Chunk benannt als **Planquadrat A1 bis L12**. Zweck: der Nutzer spricht Chunks im Chat für die Feinkalibrierung an. | ## Daten @@ -65,6 +66,34 @@ py = (slice.y1 − y) · scale = (slice.y1 + z) · scale Die Umkehrung dient den Klicks. `mapMath.js` ist die **einzige** Stelle, an der die Achsenumkehr zwischen three.js-z und Karten-y steht — genau dort würde sonst eine gespiegelte Karte entstehen. +## Chunk-Raster und Namen + +Die Namen sind die Schnittstelle zwischen Nutzer und Feinkalibrierung: was im Chat „C10" heißt, muss auf der Karte, in den Dateinamen und in der Pipeline eindeutig dasselbe sein. + +**Schema:** Spalte als Buchstabe `A` bis `L` aus `i`, Zeile als Zahl `1` bis `12` aus `j`. + +``` +name(i, j) = "ABCDEFGHIJKL"[i] + (j + 1) +``` + +**Richtung, gegen die Daten geprüft:** `chunkOrigin(i, j)` liefert `ox = x0 + i · 250` und `oy = y1 − j · 250`. `i` wächst also nach Osten, `j` von der Nordkante nach Süden. Damit gilt: + +| Name | Datei | Lage | +|---|---|---| +| A1 | `chunk_0_0.json` | Nordwest-Ecke, oben links auf der Karte | +| L1 | `chunk_11_0.json` | Nordost-Ecke | +| A12 | `chunk_0_11.json` | Südwest-Ecke | +| L12 | `chunk_11_11.json` | Südost-Ecke | +| C10 | `chunk_2_9.json` | Beispiel | + +**Eine Umrechnung, zweimal geschrieben, einmal geprüft:** `chunkName(i, j)` und `parseChunkName(name) -> { i, j }` stehen in `src/world/coords.js` neben `chunkForWorld`, und dieselben zwei Funktionen als `chunk_name` und `parse_chunk_name` in `tools/extract/leonida/coords.py` — die Feinkalibrierung wird sie in der Pipeline brauchen. Beide Seiten prüfen denselben festen Satz an Beispielen aus der Tabelle oben, damit JavaScript und Python nicht auseinanderlaufen können. `parseChunkName` akzeptiert Groß- und Kleinschreibung (`c10` = `C10`) und weist alles außerhalb von A1–L12 ab. + +**Auf der Karte:** +- Rasterlinien an allen Chunk-Grenzen. +- Der Name steht in der Mitte jedes Chunks, sobald der Chunk auf dem Bildschirm mindestens 40 px breit ist; darunter nur die Linien. Beim Öffnen passt der ganze Ausschnitt ins Fenster, dann ist jeder Chunk auf gängigen Bildschirmen breit genug. +- Unter dem Mauszeiger eine Anzeige mit Chunk-Name und Weltkoordinate, etwa `C10 · x 412 / y 1830`. Die Koordinate erlaubt, eine Stelle innerhalb eines Chunks genau zu benennen. +- Der Chunk, in dem der Spieler gerade steht, ist hervorgehoben und sein Name steht fest in einer Ecke der Karte. + ## Anbindung an vorhandene Funktionen - **Position:** über `playerPosition(player)` aus `src/player.js`. Damit fährt der Pfeil auch im Fahrzeug korrekt mit; dort liefert die Kapselposition nur einen lokalen Sitzplatz-Offset. @@ -102,6 +131,12 @@ Die Umkehrung dient den Klicks. `mapMath.js` ist die **einzige** Stelle, an der ## Prüfung +**Chunk-Namen, in beiden Sprachen mit demselben Beispielsatz (vitest und pytest):** +- `A1 ↔ (0, 0)`, `L1 ↔ (11, 0)`, `A12 ↔ (0, 11)`, `L12 ↔ (11, 11)`, `C10 ↔ (2, 9)` in beide Richtungen. +- Kleinschreibung wird akzeptiert; `M1`, `A0`, `A13`, `A`, `10` und die leere Eingabe werden abgewiesen. +- Für jeden der 144 Chunks ergibt `parseChunkName(chunkName(i, j))` wieder `(i, j)`. +- Ein Test, der die Namen mit der tatsächlichen Lage verbindet statt nur mit den Indizes: der Downtown-Kern bei Welt `(−511, 254)` ergibt über `chunkForWorld` `(i = 1, j = 8)` und damit `B9`. An der bestehenden Funktion nachgerechnet. + **Ohne Browser (vitest), für `mapMath.js`:** - `worldToMap` und `mapToWorld` an bekannten Punkten: Spawn `(1699, 3, −743)` und alle vier Ecken des Ausschnitts; dazu Hin- und Rückweg ergibt wieder den Ausgangspunkt. Ein Test, der eine gespiegelte Achse sicher fängt. - Zoomgrenzen: nie kleiner als „ganzer Ausschnitt", nie größer als vierfach; Verschiebung bleibt innerhalb des Kartenrands. @@ -123,6 +158,7 @@ Die Umkehrung dient den Klicks. `mapMath.js` ist die **einzige** Stelle, an der ## Nicht Teil dieses Entwurfs +- **Die Feinkalibrierung selbst** — wie Korrekturen je Chunk gespeichert und angewendet werden. Eigenes Teilsystem mit eigenem Entwurf; diese Spec liefert dafür nur die Namen, das Raster und die Koordinatenanzeige. - Wahrzeichen auf der Karte (vom Nutzer abgewählt). - Eine kleine Eckkarte. - Pausieren des Spiels.