Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
9.0 KiB
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 | −0.30 … −0.02 | 650.87 … 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
npm run data # extract-plan + build-site
-
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 -
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. -
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 schreibtpublic/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.
Ebene Beläge statt gewelltem Gelände
Gebaute Flächen sind eben. Für jeden Belag wird aus den Höhenkoten darin und knapp daneben eine Ebene bestimmt – Gefälle auf 5 % begrenzt, am Schwerpunkt der Koten aufgehängt, und nur Koten derselben Geländezone. 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 weiterhin 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.
Die Eibenhecke entsteht nicht aus Einzelkugeln: die Pflanzstandorte des Plans werden zu Reihen verkettet, begradigt, an scharfen Knicken getrennt und als geschnittener Heckenkörper mit gerundetem Querschnitt aufgezogen. Ebenso die Ligusterhecke (170 cm hoch, 75 cm breit). Das ist der eigentliche Sichtschutz im Garten.
Die Travertinplatten 40 × 60 × 3 cm liegen laut Plan einzeln im Dekorkies – 30 Platten, exakt an den Planpositionen, als erhabene Platten auf dem Kiesbett.
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
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.
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
25bei der Sitzmauer als 25 cm Aufkantung gelesen,35bei 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.
Bekannter Zustand des Reverse Proxy (Stand 09.09.2026)
Der Container läuft auf der VM einwandfrei (gartenvisualisierung-app-1,
Netzwerk agent-net, nginx antwortet, Traefik-Labels korrekt gesetzt), aber
Traefik registriert den Router nicht: https://garten.aicds.ch liefert 404 vom
Proxy.
Befund aus der Diagnose auf dem Server:
- Traefik läuft seit rund zwei Monaten ohne Neustart und hat seit dem 04.09.2026 keine Logzeile mehr geschrieben – auch nicht zum neuen Container.
- Bereits früher registrierte Apps funktionieren weiter (
hello-test.aicds.chantwortet mit 200),cloud.aicds.chliefert seit einem fehlgeschlagenen ACME-Renewal ebenfalls 404.
Der Docker-Provider von Traefik nimmt offenbar keine neuen Container mehr auf. Ein Neustart lässt Traefik alle laufenden Container neu einlesen:
docker restart traefik
Das unterbricht alle Dienste hinter dem Proxy für wenige Sekunden.