Design-Spec für den spielbaren Vice-City-Ausschnitt
Ausschnitt A (X -1000..2000, Y -500..2500) aus der Community-Karte YANIS v15; Kartendaten von map.gtadb.org unter CC BY 4.0. Die Spec beschreibt Rechtslage, Koordinaten, Projektstruktur, die siebenstufige Extraktion, die Laufzeit mit Chunk-Streaming, Aussehen, Fehlerbehandlung, Tests und Budgets. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
commit
a6662416a1
3 files changed
+243
No files matched your search
@@ -0,0 +1,215 @@
|
||||
# Leonida: spielbarer Ausschnitt Vice City (Vertikalschnitt)
|
||||
|
||||
- **Datum:** 2026-09-12
|
||||
- **Status:** Design freigegeben, Umsetzungsplan ausstehend
|
||||
- **Umfang:** erster von vier Teilprojekten. Ein 3 × 3 km großer Ausschnitt, durch alle Ebenen hindurch spielbar.
|
||||
|
||||
## 1. Ziel und Abgrenzung
|
||||
|
||||
Ein provisorisches, aber spielbares 3D-Blockout von Vice City und Vice Beach aus der
|
||||
Community-Karte „State of Leonida" (YANIS v15). Zu Fuß und mit dem Auto begehbar, mit
|
||||
Küste, Straßen, Brücken, extrudierten Gebäuden, Palmen und Straßenmobiliar.
|
||||
|
||||
**Ausdrücklich nicht im Umfang:** die vollen 20 × 20 km, Geländehöhen aus dem Farbcode,
|
||||
Überführungen und Tunnel als getrennte Ebenen, Dachformen, KI-Verkehr, Innenräume,
|
||||
Mobilgeräte.
|
||||
|
||||
## 2. Rechtliches und Quellen
|
||||
|
||||
| Quelle | Inhalt | Lizenz |
|
||||
|---|---|---|
|
||||
| github.com/rolux/gtadb.org @ `4093e8c874e480d47c38b37fe7a404f8b0c5275e` | Kacheln YANIS v15, 2.577 Landmarks | CC BY 4.0 |
|
||||
| github.com/rolux/gtamaplib-vc | 107 Wahrzeichen als Quader mit Höhen | Unlicense (gemeinfrei) |
|
||||
| polyhaven.com | Texturen und Requisiten | CC0 |
|
||||
| opengameart.org „Palm tree v2" (Yughues/Nobiax) | Palme, 1.032 Dreiecke | CC0 |
|
||||
| Quaternius | Figuren und Animationen (UAL) | CC0 |
|
||||
| Sketchfab „Low-poly cyberpunk SUV" (Boris731) | Fahrzeug | CC BY |
|
||||
|
||||
**Nicht verwenden:** Kacheln und Bilder von map.stateofleonida.net (deren `robots.txt`
|
||||
enthält einen ausdrücklichen Rechtevorbehalt nach Art. 4 der EU-Richtlinie 2019/790, eine
|
||||
Lizenz fehlt), YANIS v16 (beruht auf dem Cyberleek-Leak, gegen den Take-Two per DMCA
|
||||
vorgeht), Rockstar-Trailerbilder als Texturen (nur als optische Vorlage).
|
||||
|
||||
**IP-Hinweis:** Alles leitet sich von GTA VI ab. Lokal zum Basteln unproblematisch, eine
|
||||
Veröffentlichung wäre rechtlich riskant. Das ist eine Entscheidung des Nutzers.
|
||||
|
||||
Namensnennung ist Pflicht (CC BY) und steht dauerhaft im HUD.
|
||||
|
||||
## 3. Koordinaten und Ausschnitt
|
||||
|
||||
- 1 Spieleinheit = 1 Meter. gtadb-Weltursprung liegt in der Innenstadt, +Y ist Norden.
|
||||
- Kachelschema `5,{zeile},{spalte}.jpg`, Zoom 5 = exakt 1 px/m, 256 px je Kachel.
|
||||
Spalte = ⌊(X + 16384)/256⌋, Zeile = ⌊(16384 − Y)/256⌋.
|
||||
- **Ausschnitt A:** X −1000 … 2000, Y −500 … 2500.
|
||||
Kacheln: Spalten 60–71, Zeilen 54–65 = **144 Kacheln, 1,18 MB**. Mosaik 3072 × 3072 px,
|
||||
Überhang wird auf die exakten Grenzen beschnitten.
|
||||
- three.js: `x = X`, `z = −Y`. Norden liegt bei −Z. Der Ausschnitt bleibt unter 2,5 km vom
|
||||
Ursprung, eine Ursprungsverschiebung ist nicht nötig.
|
||||
- Gemessene Flächenanteile (Grundlage für die Testgrenzen): Wasser 32,3 %, Stadtfläche
|
||||
31,1 %, Gebäude 9,2 %, Straße 8,3 %, Land 6,5 %, Spekulativ-Rot 2,1 %, Grün 1,9 %,
|
||||
Sand 0,9 %. 58 von 144 Kacheln enthalten Gebäudegrundrisse, 10 sind Stadtfläche ohne.
|
||||
|
||||
## 4. Projektstruktur
|
||||
|
||||
```
|
||||
gta6/
|
||||
├── package.json three 0.184.0, three-mesh-bvh, three-player-controller (file:), vite, vitest
|
||||
├── vite.config.js resolve.dedupe ['three','three-mesh-bvh'], optimizeDeps.exclude ['three-mesh-bvh']
|
||||
├── index.html
|
||||
├── src/
|
||||
│ ├── main.js Renderer, Kamera, Player, Schleife
|
||||
│ ├── world/ Chunk-Streaming und Geometrie-Baustein (reines JS, auch in Node lauffähig)
|
||||
│ ├── characters/ Figurenauswahl und Retargeting, aus showcase.js herausgelöst
|
||||
│ └── ui/ Debug-Panel, Loader, Namensnennung
|
||||
├── public/
|
||||
│ ├── data/vice-a/ manifest.json und Chunk-Dateien (generiert, committet)
|
||||
│ ├── textures/ Poly-Haven-Texturen, 1k
|
||||
│ └── models/ Palme, Requisiten, Figuren, SUV
|
||||
├── tools/
|
||||
│ ├── extract/ Python 3.12 (uv): Kacheln → Vektoren
|
||||
│ └── assets/ Downloads, TGA→PNG, Vereinfachung
|
||||
├── three-player-controller/ Git-Submodul, gepinnt auf Upstream ac39682
|
||||
└── docs/superpowers/specs/
|
||||
```
|
||||
|
||||
**Warum die Vite-Konfiguration nötig ist:** `dist/index.mjs` des Controllers importiert
|
||||
`three` und `three-mesh-bvh` als externe Pakete. Da der Klon ein eigenes `node_modules`
|
||||
besitzt, lädt eine App ohne `resolve.dedupe` **zwei three.js-Kopien**, was `instanceof`
|
||||
bricht. Der BVH-Worker wird per dynamischem Import aus `three-mesh-bvh/src/workers/`
|
||||
geladen und darf deshalb nicht vorgebündelt werden.
|
||||
|
||||
**Git:** `.gitignore` für die beiden ZIPs (160 MB), `node_modules`, `.venv` und den
|
||||
Kachel-Cache. Der Controller kommt als Submodul auf dem unveränderten Upstream-Stand;
|
||||
die vorhandenen lokalen Showcase-Änderungen werden vorher auf einem lokalen Branch im
|
||||
Klon gesichert.
|
||||
|
||||
## 5. Abhängigkeiten
|
||||
|
||||
- **Node 26:** three 0.184.0, three-mesh-bvh, three-player-controller (file:), vite,
|
||||
lil-gui, vitest, @gltf-transform/cli 4.5.0 (nur zur Asset-Aufbereitung, braucht Node ≥ 20).
|
||||
- **Python 3.12 über uv** (bereits installiert): numpy, scipy, scikit-image, shapely,
|
||||
networkx, pillow, pytest. Alle mit Apple-Silicon-Wheels.
|
||||
- **Bewusst nicht:** `skan` (zieht numba, pandas, matplotlib nach), `buildingregulariser`
|
||||
(zieht geopandas und GDAL nach), OpenCV, GDAL/rasterio (das Mosaik ist klein genug).
|
||||
- Bordmittel: `sips` wandelt die TGA-Texturen der Palme mit Alpha-Kanal nach PNG.
|
||||
|
||||
## 6. Extraktion (`tools/extract`)
|
||||
|
||||
1. **Laden.** 144 Kacheln vom gepinnten Commit in einen Cache, der nicht committet wird.
|
||||
2. **Klassifizieren.** Medianfilter gegen JPEG-Rauschen, dann jedes Pixel zur nächsten
|
||||
Legendenfarbe im Lab-Raum. Palette einmalig an den Farbfeldern der Legende kalibriert.
|
||||
Klassen: Wasser, Land, Sand, Park, Stadtfläche, Gebäude, Straße, Gasse, Weg, Bahn,
|
||||
Spekulativ-Rot. Beschriftung, Icons und Kanten gelten als „unbekannt" und werden vom
|
||||
nächsten bekannten Nachbarpixel aufgefüllt.
|
||||
3. **Küste.** Wassermaske glätten, Landpolygone mit Löchern bilden, auf 1 m vereinfachen.
|
||||
4. **Straßen.** Kein Graph: die gezeichneten **Straßenflächen** werden übernommen (Maske
|
||||
schließen, das überbrückt Straßennamen, dann polygonisieren). Kreuzungen stimmen
|
||||
dadurch automatisch. Mittellinien entstehen zusätzlich per Skelett, nur zum Platzieren
|
||||
von Laternen. Straßenflächen über Wasser werden als **Brücken** markiert.
|
||||
5. **Gebäude.** Zusammenhängende Flächen → Konturen → Polygone. Deckt ein Polygon ≥ 85 %
|
||||
seines gedrehten Hüllrechtecks, wird es zum Rechteck, sonst auf 1 m vereinfacht.
|
||||
Unter 12 m² verwerfen. Rot = spekulativ markieren.
|
||||
6. **Höhen.** Die 54 Wahrzeichen aus gtamaplib-vc (26–248 m, Median 111 m) werden dem
|
||||
Grundriss unter ihrem Punkt zugeordnet und liefern die echte Höhe. Alle übrigen
|
||||
Gebäude bekommen Startwerte je Viertel, per Seed reproduzierbar, kleine Grundrisse
|
||||
niedriger: Downtown 20–60 m, Ocean Beach 8–25 m, sonst 6–15 m. Die Zuordnung eines Gebäudes zu einem Viertel erfolgt über das
|
||||
nächstgelegene gtadb-Landmark. Die 10 leeren
|
||||
Stadtkacheln bekommen generierte Flachbauten, als solche markiert.
|
||||
7. **Palmenpunkte.** Deterministisch, mit festem Seed: auf Parkflächen mit mindestens
|
||||
6 m Abstand zu Gebäuden und Straßen, sowie beidseitig im Abstand von 12 m entlang
|
||||
jeder Straßenmittellinie, die höchstens 40 m von einer Sandfläche entfernt liegt
|
||||
(das ist die Promenade).
|
||||
|
||||
**Ausgabe** je 250-m-Chunk eine JSON-Datei mit Koordinaten in Metern relativ zur
|
||||
Chunk-Ecke: `land[]`, `roads[]` (mit `class`, `bridge`), `centerlines[]`, `buildings[]`
|
||||
(`poly`, `height`, `source` = skyline | district | generated, `speculative`), `palms[]`.
|
||||
Dazu `manifest.json` mit Grenzen, Chunk-Liste, Quell-Commit, Parametern, Seed und
|
||||
Namensnennung. Zusätzlich ein **Debug-PNG je Chunk** mit den Vektoren über der Karte.
|
||||
|
||||
## 7. Laufzeit
|
||||
|
||||
**Streaming.** 12 × 12 Chunks à 250 m. Laden ab 400 m Entfernung, Entladen ab 600 m; der
|
||||
Abstand verhindert Flackern. Pro Frame höchstens ein Chunk-Bau und eine Collider-Anmeldung,
|
||||
bis zu vier Abmeldungen (Muster aus `example/3dtilesScene.js`). Typisch 9–16 aktive Chunks.
|
||||
Das ist zwingend, weil `CollisionWorld.query` **jeden** Collider in jedem Frame durchgeht.
|
||||
|
||||
**Geometrie je Chunk**, trianguliert mit dem in three.js enthaltenen Earcut:
|
||||
- Land: 1 m dicke Platte, Oberkante y = 0, mit Seitenwänden an der Küste
|
||||
- Straßen: flache Flächen 3 cm über dem Boden, ohne eigenen Collider
|
||||
- Brücken: 0,6 m dicke Platten mit Collider
|
||||
- Gebäude: Wände und Flachdach, je Material zu einem Mesh zusammengefasst
|
||||
- Wasser: eine Fläche für den ganzen Ausschnitt bei y = −0,6
|
||||
|
||||
**Kollision.** Genau ein Collider je Chunk (Land, Brücken, Gebäude, dazu Stammzylinder von
|
||||
Palmen und Laternen), BVH im Worker über `addCollider({ useWorker: true })`. Meeresboden
|
||||
bei y = −2,5, damit man waten kann statt zu fallen. Requisiten-Meshes selbst bleiben ohne
|
||||
Kollision.
|
||||
|
||||
**Start und Sicherheit.** Bis `player.collisionWorld.get(id).ready` für den Start-Chunk
|
||||
true meldet, schwebt der Spieler mit `setSkipCapsuleCollision(true)`; nach spätestens 15 s
|
||||
wird regulär gestartet und protokolliert. Unter y = −30 setzt `reset()` an die letzte
|
||||
sichere Position zurück.
|
||||
|
||||
**Kamera.** Near 0,1 m, Far 2500 m, Nebel verdeckt die Chunk-Grenze, Schatten folgen dem
|
||||
Spieler.
|
||||
|
||||
## 8. Aussehen und Inhalte
|
||||
|
||||
- **Materialien:** Welt-Texturkoordinaten (waagerecht aus x/z, an Wänden aus Kantenlänge
|
||||
und Höhe), damit Texturen nahtlos über Chunk-Grenzen laufen. Rund sechs Poly-Haven-
|
||||
Materialien in 1k mit je drei Maps: Asphalt, Beton, `white_stucco`, Sand, Gras, Dach.
|
||||
Asphalt bekommen Highway und Road, Beton bekommen Gasse, Weg und Brücke.
|
||||
Gebäude werden über Vertex-Farben pastellig getönt (Art déco), ohne Zusatztexturen.
|
||||
Ziel: 4–6 Draw Calls je Chunk.
|
||||
- **Wasser:** getönte Fläche mit beim Start erzeugter, kachelbarer Wellen-Normalmap,
|
||||
Spiegelung über eine Umgebungsmap statt eines Reflexionspasses.
|
||||
- **Palmen:** Nobiax-Palme, einmalig zu GLB gewandelt (TGA → PNG, Alpha-Test, Wedel
|
||||
doppelseitig), zur Laufzeit als InstancedMesh, Höhe zufällig 10–18 m. Das Modell ist
|
||||
Y-oben, Fuß bei 0, 440 Einheiten hoch; die Zielhöhe wird über einen Skalierungsfaktor
|
||||
gesetzt.
|
||||
- **Requisiten** (Poly Haven, vor dem Einbau auf ≈ 3k Dreiecke vereinfacht, Texturen 512):
|
||||
`street_lamp_02` (20.338), `painted_wooden_bench` (630), `metal_trash_can` (13.960),
|
||||
`fire_hydrant` (86.316), `concrete_road_barrier_02` (42.578).
|
||||
- **Autos:** vier SUVs an Straßenpunkten nahe dem Start, Konfiguration aus der Showcase
|
||||
übernommen. Ihre Chunks bleiben geladen, weil jedes Fahrzeug in jedem Frame Physik rechnet.
|
||||
- **Figuren:** Modul aus `showcase.js` nach `src/characters/`, inklusive Delta-Retargeting
|
||||
und ans Mesh angepasster Hitbox. Start ist die Promenade von Vice Beach bei X 1699, Y 743 (three.js: x = 1699, z = -743),
|
||||
abgeleitet aus dem Schwerpunkt der 259 Ocean-Beach-Landmarks im Ausschnitt.
|
||||
- **Debug-Panel:** Figurenauswahl, Chunk-Grenzen, Hitbox, Kartenbild auf dem Boden,
|
||||
Sichtweite, Höhenfaktor, Sprung zu einem der 54 Wahrzeichen.
|
||||
- **Namensnennung im HUD:** Kartendaten und Landmarks von map.gtadb.org (CC BY 4.0,
|
||||
YANIS v15), SUV von Boris731 (CC BY), Poly Haven, Nobiax und Quaternius (CC0).
|
||||
|
||||
## 9. Fehlerbehandlung
|
||||
|
||||
| Fall | Verhalten |
|
||||
|---|---|
|
||||
| Kachel-Download scheitert | drei Versuche mit Wartezeit, dann Abbruch mit Liste der fehlenden Kacheln |
|
||||
| über 5 % Pixel bleiben „unbekannt" | Abbruch mit Diagnosebild, Palette neu kalibrieren |
|
||||
| ungültige Polygone | `buffer(0)`, Reste verwerfen und zählen |
|
||||
| Wahrzeichen ohne Grundriss darunter | protokollieren, Viertel-Höhe verwenden |
|
||||
| Chunk lädt nicht | zwei Wiederholungen, dann flache Platzhalterfläche und Meldung |
|
||||
| BVH-Worker fällt aus | Controller rechnet synchron weiter (eingebauter Rückfall) |
|
||||
| Textur fehlt | einfarbiges Ersatzmaterial |
|
||||
| Start-Chunk nicht fertig | nach 15 s regulär starten, protokollieren |
|
||||
| Spieler unter y = −30 | `reset()` auf letzte sichere Position |
|
||||
|
||||
## 10. Tests und Budgets
|
||||
|
||||
- **pytest:** künstliche Masken (Quadrat → Rechteck, Straßenkreuz als ein Polygon, Insel
|
||||
mit Lagune behält das Loch, Wahrzeichen findet Grundriss, gleicher Seed → gleiche Höhen),
|
||||
Schema-Prüfung der Chunk-Dateien, Plausibilitätsgrenzen am echten Ausschnitt:
|
||||
Wasser 32 % ± 3, Straße 8 % ± 2, Gebäude 9 % ± 2.
|
||||
- **vitest:** Geometrie-Baustein — Dächer nach oben, Wände nach außen, UV-Bereiche,
|
||||
Koordinaten innerhalb der Chunk-Grenzen, Dreieckszahlen bei bekannter Eingabe. Dazu ein
|
||||
Node-Durchlauf über alle 144 Chunks: keine NaN, Budget eingehalten.
|
||||
- **Abnahme im Spiel:** am Strand starten, über eine Dammstraße fahren, ins Wasser waten,
|
||||
einen Wolkenkratzer erreichen, den Ausschnitt ohne Ruckler durchqueren.
|
||||
- **Budgets:** mindestens 55 FPS, unter 150 Draw Calls, Chunk-Bau unter 20 ms im
|
||||
Hauptthread.
|
||||
|
||||
## 11. Zustimmungen, die vor der Umsetzung nötig sind
|
||||
|
||||
1. Installation der Node- und Python-Pakete aus Abschnitt 5.
|
||||
2. `.gitignore` anlegen und erste Commits im bisher leeren gta6-Repository.
|
||||
3. Sicherung der bestehenden Showcase-Änderungen auf einem lokalen Branch im Controller-Klon.
|
||||
Reference in new issue
Block a user