Ablauf wie beim Hood Yard mit den gefundenen Fallstricken (Dreiecke je Knoten, Bodenplatte +6 cm, globale Materiallisten, Asset-Test je Ort, launch.json nur im Hauptordner, gl.finish-Messung, Vorwärmen prüfen) und Werkzeugen: Modell vermessen, Kartendaten eines Weltfensters, Vergleichsbild Satellit/Spiel, Screenshot-Dekodierung, erprobte Browser-Ausschnitte. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
98 lines
8.1 KiB
Markdown
98 lines
8.1 KiB
Markdown
---
|
||
name: placing-editor-models
|
||
description: Use when a model built in the three-d-stage editor (GLB export, often sent with a .mtl) should be placed 1:1 at a real-world spot in the Leonida world — "setz das an die Stelle aus dem Satellitenbild", a yard, kiosk or building next to a park or street in a Planquadrat — or when an entry in src/world/places.js has to move, look different or collide differently.
|
||
---
|
||
|
||
# Editor-Modelle in Leonida platzieren
|
||
|
||
## Überblick
|
||
|
||
Der Ablauf bleibt der des Hood Yard: Brainstorming mit der Lagefrage am Vergleichsbild → kurze Spec → Plan → Umsetzung mit Subagenten und Reviews → Browserprüfung → Gesamt-Review → Abschluss. Vorlage: `docs/superpowers/specs/2026-09-14-hood-yard-design.md` und `docs/superpowers/plans/2026-09-14-hood-yard.md`.
|
||
|
||
Neu gebaut werden muss nichts. Orte-Schicht (`src/world/places.js`), Aufbereitung (`tools/assets/places.mjs`), Bump-Erweiterung, Tests und das Vorwärmen in `main.js` gibt es schon. Ein neuer Ort besteht aus:
|
||
- einem `PLACES`-Eintrag,
|
||
- einer aufbereiteten `.glb`,
|
||
- Ergänzungen in den Materiallisten und Tests.
|
||
|
||
Die eigentliche Arbeit sind die Lage, die Materialrollen und die Prüfung im Spiel.
|
||
|
||
**Pflicht-Skills in dieser Reihenfolge:** superpowers:brainstorming, superpowers:writing-plans, superpowers:subagent-driven-development, superpowers:finishing-a-development-branch.
|
||
|
||
## Schon entschieden, nicht neu fragen
|
||
|
||
| Punkt | Festlegung |
|
||
|---|---|
|
||
| Maßstab | 1:1, three-d-stage baut in Metern; `PLACES` hat kein `scale` |
|
||
| Lage | `at` = Welt-x/-y (Minimap), `rotation` in Grad gegen den Uhrzeigersinn, Norden oben |
|
||
| Höhe | Mit Bodenplatte (flaches Teil über die ganze Grundfläche): `lift = 0,06 − t`, t = Höhe, auf der die übrigen Gruppen stehen (Hood Yard: 0,34, obwohl `ground` wegen Bordsteinen bis 0,5 reicht → −0,28). Bei 0 cm flackert der Boden, ein Podest wird zur Stolperkante. Ohne Bodenplatte: `lift = 0` |
|
||
| Radien | Vorladen 600 m, einsetzen 250 m, herausnehmen 450 m; `tests/placesSite.test.js` prüft den Chunk-Abstand |
|
||
| Aufbereitung | nur `tools/assets/places.mjs`: die gltf-transform-CLI verwirft `EXT_materials_bump`. Ergebnis < 30 MB, die Quelle kommt nie ins Repo |
|
||
| Kollision | über Materialnamen (`SOLID_MATERIALS`); Pflanzen und Kleinteile durchlässig, Stämme fest |
|
||
| Arbeitsweise | eigener Arbeitsbaum, wenn im Hauptordner fremde Änderungen liegen |
|
||
|
||
## Ablauf
|
||
|
||
1. **Modell vermessen**, die `.mtl` ignorieren:
|
||
```bash
|
||
node .claude/skills/placing-editor-models/scripts/measure-model.mjs ~/Downloads/<name>.glb <scratch>/model.json
|
||
```
|
||
- Dreiecke zählt das Skript je Knoten; die Summe über die Meshes unterschätzt bei three-d-stage stark.
|
||
- Außerdem zeigt es Bump-Materialien, Außenmaße und Baugruppen.
|
||
- **Bodenplatte suchen:** eine flache Gruppe, die x und z der Außenmaße abdeckt. Gibt es keine, ist `lift = 0`.
|
||
- **t bestimmen:** t ist das kleinste y-Minimum der übrigen Gruppen, also die Höhe, auf der sie stehen. Nicht das y-Maximum der Plattengruppe, darin stecken oft Bordsteine und Wege. Dann gilt `lift = 0,06 − t`.
|
||
- Die Wurzel-Verschiebung ist nur ein Hinweis, nicht die Plattendicke.
|
||
2. **Stelle holen:** Planquadrat → Weltbox (`parseChunkName`, `chunkOrigin` in `src/world/coords.js`), dann ein Fenster von etwa 150 × 50 m:
|
||
```bash
|
||
node .claude/skills/placing-editor-models/scripts/site-data.mjs <x0> <x1> <y0> <y1> <scratch>/site.json
|
||
```
|
||
Straßenränder, Flächen und Laternen daraus ablesen.
|
||
3. **Satellitenbild einhängen:**
|
||
- **Anker:** ein Punkt, der im Bild und in den Chunk-Daten eindeutig ist (Feldecke, Kreuzung), möglichst nah am Ziel. Echte Stadt und Spielkarte weichen voneinander ab.
|
||
- **Maßstab:** Meter pro Pixel aus Autos (~4,5 m) oder Feldmarkierungen schätzen, mit ±15 % Unsicherheit rechnen.
|
||
4. **Vergleichsbild** rendern und per `SendUserFile` schicken:
|
||
```bash
|
||
tools/extract/.venv/bin/python .claude/skills/placing-editor-models/scripts/render-site.py --site site.json --model model.json --at X Y --satellite <bild> --anchor-px PX PY --anchor-world AX AY --mpp 0.15 --out lage.png
|
||
```
|
||
- Dann genau **eine** Frage mit `AskUserQuestion`: „wie im Bild“ oder die zwei naheliegenden Verschiebungen.
|
||
- Ist die echte Anlage länger oder kürzer als das Modell, die Ausrichtung (Mitte, Anfang, Übergang zwischen Bauteilen) ausdrücklich zur Wahl stellen.
|
||
5. **Materialrollen festlegen.** `NEAR_MATERIALS` und `SIMPLIFY_RATIOS` (`places.mjs`) sowie `SOLID_MATERIALS` (`places.js`) sind global und nach Namen geordnet.
|
||
- Neue Namen gegen die Listen abgleichen. Hat derselbe Name eine andere Rolle (etwa `grass` als begehbare Fläche statt als Halme), dem Nutzer vorlegen und nicht still teilen.
|
||
- Anteile beim Vereinfachen, nach gezeichneten Dreiecken: Bäume mit mehr als 300 000 → 0,15; Gras und Büsche → 0,5; Kleinteile → 0,25; Gebäude, Boden und Zäune nie.
|
||
6. **Spec und Plan** kurz halten, nur was neu ist:
|
||
- **Spec:** Befund (Tabelle aus Schritt 1), Lage-Tabelle mit Abständen zu Straße, Feldern und Laternen, Materialrollen, Budget.
|
||
- **Plan-Tasks:**
|
||
- Materiallisten
|
||
- Aufbereitung und Asset-Test
|
||
- `PLACES`-Eintrag und Lage-Test
|
||
- Browserprüfung
|
||
7. **Aufbereiten:** `node tools/assets/places.mjs <quelle.glb> <id>`. Aus dem Bericht die `bounds` in `PLACES` übernehmen; `gpuMB` und die Dreieckszahl mit dem Nutzer abgleichen, wenn sie deutlich über dem Hood Yard liegen (231 MB, 658 000).
|
||
8. **Tests:**
|
||
- `tests/placesSite.test.js` prüft jeden `PLACES`-Eintrag schon von selbst.
|
||
- `tests/placesAsset.test.js` ist auf `hood-yard` zugeschnitten. Beim zweiten Ort auf `describe.each(PLACES)` umbauen: feste Materialien **je Ort** prüfen statt ganz `SOLID_MATERIALS`, die Bump-Prüfung nur dort, wo das Modell Bump hat.
|
||
9. **Browserprüfung** nach `browser-checks.md`:
|
||
- Lage prüfen.
|
||
- Kollision: Kapsel steht auf der Platte, eine Wand stoppt sie, Pflanzen sind durchlässig.
|
||
- Drei Blicke als Bilder an den Nutzer.
|
||
- Kosten mit `gl.finish` messen, mit und ohne Ort.
|
||
- Vorwärmen: Texturzähler am Startpunkt ablesen.
|
||
10. **Gesamt-Review, Abnahme durch den Nutzer, Branch abschließen.**
|
||
|
||
## Fallstricke
|
||
|
||
| Symptom | Ursache | Gegenmittel |
|
||
|---|---|---|
|
||
| Dreieckszahl viel kleiner als gezeichnet | three-d-stage benutzt Meshes mehrfach | je Knoten zählen (`measure-model.mjs`) |
|
||
| Wellblech, Relief oder Rillen flach | gltf-transform-CLI verwirft `EXT_materials_bump` | nur `places.mjs` |
|
||
| Figur läuft durch Wände, steht bei y 0,75 statt auf der Platte | meshopt-Positionen sind quantisiert, der Collider-Bau klemmt sie auf ±1 | Orte immer über `prepareModel`/`PlaceLayer` einsetzen; im Browser prüfen, dass feste Meshes Float32 haben |
|
||
| Boden flackert im Ort | Plattenoberkante auf y 0 | `lift` für +6 cm |
|
||
| Laterne oder Palme steht im Ort | Requisiten entstehen je Chunk, Laternen bis 16 m neben der Mittellinie, auch aus Nachbarchunks | Site-Test, Lage verschieben |
|
||
| Ort schwebt nach einem Minimap-Sprung kurz über dem Meer | der Streamer baut einen Chunk pro Frame | hingenommen (Ruling Hood Yard) |
|
||
| Asset-Test wird mit dem zweiten Ort rot | globaler `SOLID_MATERIALS`-Check | je Ort prüfen (Schritt 8) |
|
||
| `preview_start` findet den Server nicht | liest nur `.claude/launch.json` des Hauptordners | Nutzer fragen, Arbeitsbaum kurz verlassen, Eintrag setzen, zurück, am Ende entfernen |
|
||
| Befehle im Arbeitsbaum verweigert | Isolationswache mag keine Variablen als Befehl oder Skriptpfade mit Leerzeichen | Pfade ausschreiben; statt `review-package` drei Befehle: `git log --oneline A..B >`, `git diff --stat A..B >>`, `git diff -U10 A..B >>` in eine Datei |
|
||
| Draw-Call- und Dreieckszahlen zu optimistisch | `renderer.info` wird nach den Schattenstufen zurückgesetzt | `gl.finish`-Messung (`browser-checks.md` §8) |
|
||
| Ruckler beim ersten Erscheinen | Vorwärmen lief nicht | am Startpunkt muss `renderer.info.memory.textures` die Texturen des Orts schon enthalten |
|
||
| Seite friert nach einem Browser-Hook ein | Ausnahme im `onBeforeRender`-Hook beendet die Zeichenschleife | `window.__probe ??= {}`, nach Vite-Reload neu einrichten |
|
||
|
||
Werkzeuge: `scripts/` (Vermessung, Kartendaten, Vergleichsbild, Screenshot-Dekodierung); Browser-Ausschnitte: `browser-checks.md`.
|