Deploy App / deploy (push) Successful in 28s
- Ein Klick faengt die Maus ein, danach dreht die blosse Mausbewegung den Blick. Maus nach rechts oben heisst Blick nach rechts oben. Esc gibt die Maus wieder frei, das Fadenkreuz zeigt den Zustand an. - Ohne Mausfang (direkt nach Esc oder wo er gesperrt ist, etwa in eingebetteten Vorschauen) dreht Ziehen den Blick in derselben Richtung - vorher zog man die Szene, was sich verkehrt anfuehlte. - Am Handy wischt man jetzt ebenfalls in die Blickrichtung statt dagegen. - Mit gefangener Maus fuehrt ein Klick zu dem Punkt unter dem Fadenkreuz, ohne Mausfang weiterhin zum angeklickten Punkt. - Beim Wechsel in die Uebersicht wird der Mausfang freigegeben. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
394 lines
19 KiB
Markdown
394 lines
19 KiB
Markdown
# Gartenvisualisierung Egglihaldenstrasse 9a
|
||
|
||
Begehbare 3D-Visualisierung des geplanten Gartens von Jasmin und Damian
|
||
Kellenberger, Egglihaldenstrasse 9a, 9030 Abtwil SG.
|
||
|
||
Live: **https://garten.aicds.ch**
|
||
|
||
Die gesamte Geometrie ist **massstäblich aus dem Gartenplan** abgeleitet – nicht
|
||
nachmodelliert. Ein Node-Werkzeug liest die Vektordaten direkt aus dem Plan-PDF,
|
||
rechnet sie in Meter um und erzeugt daraus das Szenenmodell.
|
||
|
||
---
|
||
|
||
## Grundlagen
|
||
|
||
| Quelle | Inhalt |
|
||
|---|---|
|
||
| `Info Dateien/Gartenplan 1 …pdf` | Garten Design AG, 14.08.2026, Massstab 1:100, A1 |
|
||
| `Info Dateien/20210427 - Projektpläne Haus 9a.pdf` | EHLE Architekten AG, Grundrisse, Fassaden, Umgebung |
|
||
| `Info Dateien/WhatsApp Image …jpeg` | Fotos des Ist-Zustands (Fassade, Beläge, Nachbarschaft) |
|
||
|
||
Die DWG wird nicht benötigt – das PDF enthält dieselbe Vektorgeometrie.
|
||
|
||
### Koordinatensystem
|
||
|
||
Alles rechnet im **Site-Frame**, in Metern:
|
||
|
||
- **X** – Hausachse ENE, Peilung 61.1615° gegen Nord
|
||
- **Z** – senkrecht dazu, SSE, Peilung 151.1615°
|
||
- **Y** – Höhe über dem Fixpunkt `0.00` = **651.17 m ü. M.** (OK Fertigboden EG)
|
||
|
||
Der Nordpfeil des Plans zeigt exakt zur Blattoberkante, das Zeichnungsraster
|
||
liegt um −28.8385° gedreht dazu. Der Massstab ist über das Plattenraster
|
||
verifiziert: die Keramikplatten messen sich auf 0.600 m genau.
|
||
|
||
### Höhen
|
||
|
||
| Bezug | relativ | absolut |
|
||
|---|---|---|
|
||
| Feuerwehrzufahrt, Nordwestecke | −2.08 | 648.09 m |
|
||
| Nachbargarten Zollet (Haus 9, OK FB EG) | −1.70 | 649.47 m |
|
||
| Hauptsitzplatz Travertin (untere Ebene) | −0.33 | 650.84 m |
|
||
| Rasen und Kiesfeld (obere Ebene) | −0.02 | 651.15 m |
|
||
| Fixpunkt Hauseingang | 0.00 | 651.17 m |
|
||
| Ostseite beim Apfelbaum | +0.63 | 651.80 m |
|
||
| OK Fertigboden Obergeschoss | +2.90 | 654.07 m |
|
||
| OK Attika Haus 9a | +6.15 | 657.32 m |
|
||
|
||
---
|
||
|
||
## Datenpipeline
|
||
|
||
```bash
|
||
npm run data # extract-plan + build-site
|
||
```
|
||
|
||
1. **`tools/extract-plan.mjs`** – öffnet das Plan-PDF mit MuPDF (WASM) und
|
||
protokolliert alle Zeichenoperationen mit. Ergebnis: rund 5400 Polygone,
|
||
234 Pflanzenkreise, 229 Beschriftungen und 46 Höhenkoten, transformiert in
|
||
den Site-Frame. → `tools/out/plan-raw.json`
|
||
|
||
2. **`tools/authoring.mjs`** – handgepflegte Ergänzungen: Zuordnung der
|
||
Planfarben zu Belagsarten, Mauerachsen und -höhen, Gebäudekubatur,
|
||
Geländezonen, Standorte. Alles kommentiert und auf Plan oder
|
||
Architekturpläne zurückgeführt.
|
||
|
||
3. **`tools/build-site.mjs`** – klassiert die Flächen, leitet Pflanzen und
|
||
Leuchten ab, interpoliert das Geländeraster (0.25 m) aus den Höhenkoten je
|
||
Zone und schreibt `public/data/site.json` (rund 110 kB).
|
||
|
||
Zur Kontrolle: `node tools/debug-svg.mjs` zeichnet die extrahierte Geometrie als
|
||
SVG-Draufsicht, `node tools/inspect-colors.mjs` listet die Planfarben mit den
|
||
nächstgelegenen Beschriftungen.
|
||
|
||
### Die beiden Ebenen
|
||
|
||
Der Garten liegt auf zwei Niveaus, und der Sprung dazwischen ist ein Bauteil:
|
||
|
||
| | |
|
||
|---|---|
|
||
| Untere Ebene – Hauptsitzplatz Travertin | **−0.33 m** |
|
||
| Travertinsitzmauer, Ansichtshöhe | **0.31 m** |
|
||
| Obere Ebene – Rasen, Kiesfeld, Flammengrill | **−0.02 m** |
|
||
| Gedeckter Sitzplatz | −0.02 m |
|
||
| Zwei schwebende Travertinstufen dazwischen | −0.17 / −0.31 m |
|
||
|
||
Gegen Osten steigt der Garten laut Plan weiter an (0.26 bis 0.63 m); dort bleibt
|
||
die aus den Koten ausgeglichene Ebene stehen. Die beiden Hauptniveaus stehen als
|
||
`LEVELS` in `tools/authoring.mjs` und werden nicht geschätzt – Flächen, deren
|
||
Schwerpunkt darin liegt, bekommen exakt dieses Niveau.
|
||
|
||
### Der Sichtschutz
|
||
|
||
Er ist bewusst **nicht durchgehend**. Der Plan zeichnet ihn als Wechsel von
|
||
aufrechten **Travertinstelen** (50 × 6 cm, in Dreiergruppen) und
|
||
**Eibengruppen**, alle zusammen in einem **Dekorkiesbett**. Die 28 Stelen kommen
|
||
mit Position und Ausrichtung direkt aus dem Plan; die Eiben werden nur innerhalb
|
||
einer Gruppe zu einem Heckenkörper verkettet, damit die Lücken für die Stelen
|
||
offen bleiben.
|
||
|
||
Höhen nach Abschirmrichtung:
|
||
|
||
- gegen den Südnachbarn, entlang der langen Fläche: **1.80 m**
|
||
- gegen Zollet und die Feuerwehrzufahrt, untere Ebene: **1.50 m**
|
||
|
||
### Ebene Beläge statt gewelltem Gelände
|
||
|
||
Gebaute Flächen sind eben. Wo kein festes Niveau vorgegeben ist, wird aus den
|
||
Höhenkoten eine Ausgleichsebene bestimmt – Gefälle auf 4 % begrenzt, am
|
||
Schwerpunkt der Koten aufgehängt. Jede Kote gehört dabei zu genau **einer**
|
||
Fläche, nämlich der kleinsten, die sie enthält; sonst zieht etwa die Kote einer
|
||
Stufe die darunterliegende Terrasse mit hoch und aus zwei sauberen Ebenen wird
|
||
eine schiefe.
|
||
|
||
Das Geländeraster wird in diesen Feldern auf die Ebene gezwungen und dort
|
||
**nicht** geglättet. Im Rendering bekommt jeder Belag eine senkrechte Sichtkante
|
||
zum angrenzenden Gelände – erst dadurch wirkt eine Terrasse gebaut und nicht
|
||
aufgemalt. Wachsende Flächen (Rasen, Schotterwiese, Beet) folgen dem Gelände.
|
||
|
||
### Bauteile statt hochgezogener Flächen
|
||
|
||
Der Plan nennt vier verschiedene Konstruktionen, und sie sehen auch verschieden
|
||
aus (`src/scene/walls.ts`):
|
||
|
||
- **Travertinmauer / Sitzmauern** – Schichtmauerwerk aus einzelnen Blöcken mit
|
||
versetzten Stossfugen und überstehender Abdeckplatte.
|
||
- **Winkelelemente aus Beton** – Fertigteile von 1 m Breite, einzeln versetzt,
|
||
mit Stossfugen, nach unten dicker werdendem Stiel und Fussplatte.
|
||
- **Betonmauer Nachbar** – Ortbeton in Schaltafelfeldern mit abgefaster Krone.
|
||
- **Lamellenwand** – senkrechte Bretter im Rhythmus des Plans (10 cm breit,
|
||
35 cm tief, 90 cm Achsabstand) vor dem gedeckten Sitzplatz.
|
||
- **Holzscheiterwand** – Stahlrahmen, gefüllt mit gestapelten Scheitern.
|
||
- **Treppen mit Rampe, Geländer und Rinnen** – die linearen Bauteile aus
|
||
`LINEAR` in `tools/authoring.mjs`, gerendert in `src/scene/structures.ts`:
|
||
Blockstufen aus Travertin, Stahlrohrgeländer mit Hand- und Knieholm entlang
|
||
des Gefälles, Entwässerungsrinnen mit bündigem Rost.
|
||
- **Gartentor** – Stabgitterflügel von 100 cm mit zwei Pfosten und senkrechten
|
||
Stäben, nicht als geschlossenes Blatt.
|
||
- **Spielhaus** – ein Stelzenhaus. Der Plan zeichnet zwei Rechtecke: das Podest
|
||
1.81 × 2.70 m mit der Kote 1.47 (rund 0.9 m über dem Gelände) und darauf an
|
||
der Ostseite die Hütte 1.01 × 2.70 m. Der westliche Teil bleibt offene
|
||
Plattform mit Brüstung und Leiter.
|
||
|
||
Die **Eibengruppen** entstehen nicht aus Einzelkugeln: die Pflanzstandorte des
|
||
Plans werden gruppenweise verkettet, begradigt, an scharfen Knicken getrennt und
|
||
als geschnittener Heckenkörper mit gerundetem Querschnitt aufgezogen – siehe
|
||
Abschnitt „Der Sichtschutz". Ebenso die Ligusterhecke (170 cm, 75 cm breit).
|
||
|
||
Die **Travertinplatten 40 × 60 × 3 cm** liegen laut Plan einzeln im Dekorkies –
|
||
30 Platten, exakt an den Planpositionen, als erhabene Platten auf dem Kiesbett.
|
||
|
||
Die **Rasenrandplatten** sind im Plan ein durchgehendes Band von 6 cm Breite
|
||
zwischen Rasen und Kiesbett des Sichtschutzes. Sie werden nicht als Belag,
|
||
sondern als hochkant stehende Randplatte mit sichtbarer Kante aufgebaut
|
||
(Belagstyp `randplatte`).
|
||
|
||
Am **Gartentor** liegen ebenfalls zwei schwebende Travertinstufen: der Plan
|
||
zeichnet dort ein Feld von 0.80 × 1.60 m mit den Koten −0.13 (Podest am Tor)
|
||
und −0.32 (Anschluss an den Hauptsitzplatz).
|
||
|
||
Der Plan zeigt **zwei** orange markierte Felder von 1.50 × 0.46 m in der
|
||
Sichtschutzlinie; die Beschriftung „Holzscheiterwand 150 cm x 200 cm" steht
|
||
zwischen ihnen und gilt für beide.
|
||
|
||
Materialien und Ausbildung folgen den **Referenzbildern im Plan-PDF**: heller,
|
||
geschichteter Travertin für Mauern, Stelen und Platten, die schwebenden Stufen
|
||
als auskragende Platten mit Schattenfuge, der Flammengrill als anthrazitfarbener
|
||
Stahlkubus mit Holzfach und runder Feueröffnung. Die Bilder lassen sich mit
|
||
`node tools/plan-bilder.mjs` aus dem PDF ziehen.
|
||
|
||
### Ebene Ebenen, geneigte Wege
|
||
|
||
`LEVELS` in `tools/authoring.mjs` gibt einzelnen Bereichen ihre Höhe fest vor,
|
||
statt sie aus streuenden Koten zu schätzen. Zwei Formen:
|
||
|
||
- **`level` + `flatten`** – waagrecht und zwingend. Die obere Ebene mit Rasen
|
||
und Kiesfeld liegt eben auf −0.02. Ohne diese Vorgabe zieht die Interpolation
|
||
den Rasen hügelig hoch, weil die Koten 0.09 bis 0.26 schon im angehobenen
|
||
Kiesbett des Sichtschutzes liegen und nicht mehr im Rasen.
|
||
- **`plane`** – eine geneigte Ebene, für die Wege. Sie sind Rampen, keine
|
||
waagrechten Felder: Ostweg rund 12 %, Weg an der Südgrenze rund 3 %,
|
||
Feuerwehrzufahrt rund 13.6 % (Plankoten −2.08 und −1.08). Der
|
||
Architekturplan (`Erdgeschoss mit Umgebung 1:100`) beschriftet dieselben
|
||
Gefälle mit „Steigung 9.9 %“ und „Steigung 13.0 %“.
|
||
|
||
Ausserhalb aller Zonen wird die Interpolation der nächstgelegenen Zone
|
||
fortgesetzt, nicht ihr konstanter Ersatzwert – sonst steht der Belag als
|
||
schwebende Platte über einer Geländekante.
|
||
|
||
### Das Haus nach den Fassadenplänen
|
||
|
||
Die Öffnungen sind aus den Fassadenplänen von EHLE Architekten (1:100)
|
||
abgegriffen. Die Pläne benennen die Fassaden nach Himmelsrichtung, das
|
||
Datenmodell nach Achsrichtung:
|
||
|
||
| Plan | Site | Lage |
|
||
| --- | --- | --- |
|
||
| Südostfassade | `south`, z +0.96 | lang, zum Garten |
|
||
| Nordostfassade | `east`, x +0.28 | kurz, Hauszugang |
|
||
| Südwestfassade | `west`, x −13.82 | kurz, zur Terrasse |
|
||
| Nordwestfassade | `north`, z −6.87 | lang, zum Nachbarn – im Plansatz nicht gezeichnet, bleibt geschlossen |
|
||
|
||
Zum Garten steht im Erdgeschoss **eine** mittige Fensterfront, daneben das
|
||
Lamellenband vor dem gedeckten Sitzplatz; im Obergeschoss zwei Fenster mit zwei
|
||
schmalen Lamellen dazwischen. Der gedeckte Sitzplatz ist **nur gegen Westen
|
||
offen** („Aussensitzplatz“ in der Südwestfassade) – gegen den Garten steht dort
|
||
eine geschlossene Wand. Ohne sie schaut man von aussen durch die Fassade in den
|
||
Sitzplatz hinein.
|
||
|
||
### Zwei Darstellungen
|
||
|
||
Oben in der Mitte schaltet ein Knopf zwischen **Stilisiert** und
|
||
**Fotorealistisch**. Beide Varianten entstehen aus derselben Geometrie – Plan,
|
||
Masse, Höhen und Rundgang sind identisch. Die Bauteile fragen beim Aufbau
|
||
`isFoto()` ab (`src/scene/quality.ts`). Die zweite Variante wird beim ersten
|
||
Umschalten aufgebaut und bleibt danach im Speicher, so springt man ohne
|
||
Wartezeit hin und her. Die Wahl merkt sich der Browser; `?ansicht=foto` oder
|
||
`?ansicht=stil` erzwingt eine Variante.
|
||
|
||
Was die fotorealistische Variante anders macht:
|
||
|
||
| Bereich | Umsetzung |
|
||
| --- | --- |
|
||
| Materialien | **Fotografierte Materialien von ambientCG (CC0)** für Travertin, Pflaster, Kies, Sand, Erde, Rasen, Holzschalung, Beton und Keramik – Liste in `public/materialien/QUELLEN.md`, rund 11 MB, erst beim Umschalten geladen (`fotomaterial.ts`). Plattenbeläge werden aus Fotoausschnitten zusammengesetzt, jede Platte mit eigenem Ausschnitt und echten Fugen. Was kein Foto hat, wird doppelt so fein gezeichnet |
|
||
| Laub | Blattkarten statt Laubkörpern: Blätter, Eibennadeln, Ligusterblätter als Textur mit Alpha-Test, als InstancedMesh. Die Lichtnormalen zeigen vom Kronenmittelpunkt weg – so wird eine Krone als Volumen beleuchtet (`laub.ts`) |
|
||
| Bäume | Rekursiv gewachsene, gekrümmte Äste; Blattwolken an den Zweigspitzen |
|
||
| Rasen | Grasnarbe aus Büscheln einzelner Halme, die im Wind wiegen (`gras.ts`) |
|
||
| Himmel | Physikalisches Streumodell (`Sky`), daraus eine Umgebungskarte für Himmelslicht und Spiegelungen. In der Dämmerung wird der Verlaufshimmel eingeblendet, weil das Streumodell kein Blau der blauen Stunde kennt |
|
||
| Wiese | Kachel in zwei Massstäben gemischt und grossflächig variiert, damit das Wiederholungsmuster verschwindet |
|
||
|
||
### Damit es flüssig läuft
|
||
|
||
Die erste Fassung der Fotoansicht lief weder auf dem Handy noch auf dem Laptop
|
||
rund. Gemessen (Software-Renderer, relativ) war sie pro Bild rund 3,5-mal so
|
||
teuer wie die stilisierte – ohne die Nachbearbeitung. Was geändert wurde:
|
||
|
||
| Massnahme | Wirkung |
|
||
| --- | --- |
|
||
| **Statische Schatten**: Schattenkarten werden nur neu gerechnet, wenn die Sonne wandert, die Ansicht wechselt oder das Tor schwingt (`shadowMap.autoUpdate = false`) | beide Ansichten rund 4-mal schneller |
|
||
| **Keine Nachbearbeitung** mehr (GTAO und Bloom): GTAO hat die ganze Szene ein zweites Mal gezeichnet | grösster Einzelposten der alten Fassung |
|
||
| **Gras in Felder von 3 × 3 m** aufgeteilt, nur bis 22 m Entfernung gezeichnet, Dichte halbiert | Gras fällt kaum mehr ins Gewicht |
|
||
| **Blattkarten mit Lambert** statt physikalischer Beleuchtung, Eigenleuchten als Himmelsfüllung; rund ein Drittel so viele Karten | Laub rund 30 % günstiger |
|
||
| **Anpassungsfähige Auflösung**: fällt die Bildrate unter rund 40 Bilder/s, sinkt die Pixeldichte schrittweise (bis 0,55), bei Reserve steigt sie wieder | hält jedes Gerät flüssig |
|
||
| **Ruhe, wenn nichts passiert**: ohne Bewegung wird nach knapp 2 s nicht mehr gezeichnet | Handys werden nicht warm und drosseln nicht |
|
||
| **Handy** (Zeiger ohne Maus): 55 % der Blätter und Halme, Travertin 1024 statt 2048 px, Schatten 2048 statt 4096 | |
|
||
|
||
Insgesamt braucht ein Bild im Fotomodus jetzt rund ein Fünftel der
|
||
ursprünglichen Rechenzeit.
|
||
|
||
### Rundgang
|
||
|
||
Umsehen wie in einem Ego-Shooter: **ein Klick fängt die Maus ein**, danach dreht
|
||
schon die blosse Mausbewegung den Blick – Maus nach rechts oben heisst Blick
|
||
nach rechts oben. `Esc` gibt die Maus wieder frei. Solange sie frei ist (direkt
|
||
nach `Esc`, oder wenn der Mausfang gesperrt ist, etwa in eingebetteten
|
||
Vorschauen), dreht **Ziehen** den Blick auf dieselbe Weise. Am Handy wischt man
|
||
in die Richtung, in die man schauen will.
|
||
|
||
Gehen: `W A S D` oder Pfeiltasten, `Shift` rennt, `Leertaste` springt, am Handy
|
||
der Joystick. Ein **Klick auf den Boden** (am Handy tippen) läuft dorthin – mit
|
||
gefangener Maus zu dem Punkt unter dem Fadenkreuz.
|
||
|
||
Damit es nicht ruppig wirkt:
|
||
|
||
- Der Spieler beschleunigt und bremst weich und rutscht an Hindernissen entlang.
|
||
- Höhenwechsel bis 60 cm werden gedämpft nachgeführt, hinauf wie hinunter. Nur
|
||
bei grösseren Abstürzen oder im Sprung wirkt die Schwerkraft. Tiefer als
|
||
1.20 m läuft man nicht einfach von einer Mauer hinunter.
|
||
- Stufen, Treppen und **Travertinmauern mit fester Krone** sind begehbar: ihre
|
||
Oberkante geht in die Höhenabfrage ein (`walkHeight` in `main.ts`,
|
||
`treppeTritte` in `structures.ts`). Ob man hinaufkommt, entscheidet nur die
|
||
Stufenhöhe (45 cm). Holz-, Lamellen- und Betonwände bleiben Hindernisse.
|
||
- In der **Übersicht** dreht Ziehen die Ansicht; gezoomt wird mit dem Mausrad
|
||
(auch mit `Strg`, wobei der Seitenzoom des Browsers unterdrückt wird) und am
|
||
Handy mit zwei Fingern. Abstand 9 bis 120 m.
|
||
- Das **Gartentor** öffnet sich, wenn man darauf zugeht, und schliesst sich
|
||
hinter einem wieder; `E` übersteuert das von Hand. Im Durchgang selbst
|
||
schliesst es nie.
|
||
|
||
### Warum Zonen statt eines einzigen Geländes
|
||
|
||
Das Grundstück fällt über rund 3.5 m ab, die Sprünge liegen aber nicht im
|
||
Gelände, sondern in den Stützbauten: Travertinmauer zum Nachbargrundstück,
|
||
Winkelelemente aus Beton entlang der Feuerwehrzufahrt, Betonmauer im Süden.
|
||
Deshalb wird je Zone getrennt interpoliert – über die Zonengrenze hinweg nie.
|
||
Die Mauern erhalten ihr Kronen- und Fussprofil aus dem Gelände beider Seiten.
|
||
|
||
---
|
||
|
||
## Anwendung
|
||
|
||
```bash
|
||
npm install
|
||
npm run dev # http://localhost:5173
|
||
npm run build # dist/, rund 640 kB
|
||
```
|
||
|
||
Stack: Vite + TypeScript + three.js. **Keine externen Assets** – sämtliche
|
||
Texturen (Travertin, Keramik, Tegula, Rasen, Kies, Beton, Holzschalung,
|
||
Scheiterwand) werden zur Laufzeit prozedural auf ein Canvas gezeichnet. Die UVs
|
||
sind weltbezogen, damit die Plattenraster über Flächengrenzen hinweg durchlaufen
|
||
– so wie auf dem Plan.
|
||
|
||
### Bedienung
|
||
|
||
| | |
|
||
|---|---|
|
||
| Rundgang | Klicken, dann `W` `A` `S` `D`, `Shift` zum Rennen, `Esc` gibt die Maus frei |
|
||
| Handy | links Joystick, rechts wischen zum Umsehen |
|
||
| Übersicht | ziehen zum Drehen, Mausrad zum Zoomen |
|
||
| Tageszeit | Regler oben rechts, Sonnenstand astronomisch für Abtwil SG gerechnet |
|
||
|
||
Der Rundgang folgt dem Gelände, steigt Stufen bis 45 cm und wird von Mauern,
|
||
Gebäuden, Hecken und Objekten aufgehalten. Ab Dämmerung schalten die 17 Leuchten
|
||
des Plans automatisch ein.
|
||
|
||
### Aufbau
|
||
|
||
```
|
||
src/
|
||
site.ts Datenmodell und Höhen-Sampler
|
||
scene/textures.ts prozedurale Beläge und Materialien
|
||
scene/geometry.ts Polygone auf das Gelände legen, Mauern extrudieren
|
||
scene/terrain.ts Geländeraster und Umland
|
||
scene/surfaces.ts Beläge
|
||
scene/walls.ts Mauern als Bauteile: Schichtmauerwerk, Winkelelemente, Lamellen
|
||
scene/structures.ts Stelen, Objekte, Leuchten
|
||
scene/vegetation.ts Gehölze, Hecken, Gräser, Stauden
|
||
scene/building.ts Wohnhaus 9a und Nachbargebäude
|
||
scene/environment.ts Himmel, Sonnenstand, Licht
|
||
controls/walker.ts Begehen mit Kollision und Geländeführung
|
||
ui/hud.ts Bedienoberfläche
|
||
```
|
||
|
||
---
|
||
|
||
## Deployment
|
||
|
||
Push auf `main` löst den Gitea-Workflow aus; die App landet unter
|
||
`/opt/aicds/apps/Gartenvisualisierung/` und wird per `docker compose` gebaut.
|
||
Traefik-Router `garten`, Host `garten.aicds.ch`, Netzwerk `agent-net`.
|
||
|
||
```bash
|
||
docker compose config # Prüfung vor dem Push
|
||
docker compose up -d --build
|
||
```
|
||
|
||
Das Image enthält nur `dist/` hinter nginx – die Planunterlagen und Fotos aus
|
||
`Info Dateien/` werden über `.dockerignore` ausgeschlossen und gelangen nie in
|
||
den Webcontainer.
|
||
|
||
---
|
||
|
||
## Was bewusst interpretiert ist
|
||
|
||
Der Plan ist ein Situationsplan; einiges steht nur als Beschriftung darin. Diese
|
||
Annahmen stecken in `tools/authoring.mjs` und sind dort einzeln kommentiert:
|
||
|
||
- **Mauerhöhen** aus den Höhenkoten beidseits abgeleitet; die gelbe Kote `25`
|
||
bei der Sitzmauer als 25 cm Aufkantung gelesen, `35` bei den Heidelbeeren
|
||
analog.
|
||
- **Lamellenwand zum Sitzen** als senkrechte Holzlamellen im Planrhythmus
|
||
(10 cm breit, 35 cm tief, rund 90 cm Achsabstand), passend zum Foto des
|
||
Ist-Zustands.
|
||
- **Wohnhaus** in Kubatur und Öffnungen nach Gartenplan und Fassadenplänen,
|
||
Materialisierung nach den Fotos: vertikale Holzschalung graubraun, heller
|
||
Betonsockel, Flachdach mit extensiver Begrünung.
|
||
- **Nachbarhaus Zollet** als einfaches Kontextvolumen, 1.70 m tiefer liegend.
|
||
- **Solitärgehölze** mit den Kronenradien des Plans; Wuchshöhen als
|
||
Erfahrungswerte.
|
||
- **Gartenhaus, Spielhaus, Flammengrill, Bänkli** in Lage und Grundfläche nach
|
||
Plan, in der Ausformulierung frei.
|
||
|
||
---
|
||
|
||
## Stolperstein beim Deployment
|
||
|
||
Der erste Rollout lieferte trotz laufendem Container und korrekten Traefik-Labels
|
||
ein 404 vom Proxy. Ursache war der HEALTHCHECK im Dockerfile: busybox-`wget`
|
||
löst `localhost` zuerst nach `::1` auf, nginx lauschte aber nur auf IPv4 – der
|
||
Check schlug dauerhaft fehl und der Container blieb auf `health: starting`.
|
||
|
||
**Traefik nimmt Container, die nicht `healthy` sind, gar nicht in die
|
||
Routing-Tabelle auf.** Deshalb entstand kein Router, kein Zertifikat und damit
|
||
ein 404 mit dem Traefik-Default-Zertifikat – ein Fehlerbild, das leicht nach
|
||
einem Proxy- oder DNS-Problem aussieht.
|
||
|
||
Behoben durch `http://127.0.0.1/` im Healthcheck und ein zusätzliches
|
||
`listen [::]:80;` in der nginx-Konfiguration. Der Deploy-Workflow wartet
|
||
seither auf `healthy` und prüft den Router, bevor er den Lauf abschliesst.
|
||
|
||
Merksatz für weitere AICDS-Apps: ein Container mit fehlschlagendem Healthcheck
|
||
wird von Traefik stillschweigend ignoriert.
|