Files
Gartenvisualisierung/README.md
T
admGitAICDSandClaude Opus 5 5b1cf9d0d9
Deploy App / deploy (push) Successful in 28s
Sichtschutz, schwebende Stufen und Hoehenprofil nach Plandurchgang
Nach erneutem Detailstudium des Gartenplans und der Referenzbilder darin:

- Sichtschutz ist nicht durchgehend: 28 aufrechte Travertinstelen (50x6 cm,
  Dreiergruppen, Positionen direkt aus dem Plan) wechseln sich mit
  Eibengruppen ab, alle in einem Dekorkiesbett. Hoehe 1.80 m gegen den
  Suednachbarn, 1.50 m gegen Zollet auf der unteren Ebene.
- Zwei schwebende Travertinstufen fuehren vom gedeckten Sitzplatz (-0.02)
  auf den Hauptsitzplatz hinunter, als auskragende Platten mit Schattenfuge.
- Hoehenprofil auf zwei klare Ebenen gebracht: untere Ebene -0.33,
  Travertinsitzmauer mit 31 cm Ansicht, obere Ebene -0.02. Die Niveaus stehen
  fest in LEVELS statt aus streuenden Koten geschaetzt zu werden.
- Jede Hoehenkote gehoert neu zu genau einer Flaeche, der kleinsten, die sie
  enthaelt - sonst kippen benachbarte Ebenen ineinander.
- Der schmale Streifen am Sichtschutz ist Kiesbett, nicht Plattenbelag.
- Travertin nach den Referenzbildern deutlich heller, eigene Steintextur fuer
  die Stelen; Flammengrill als Stahlkubus mit Holzfach und Feueroeffnung.
- Stirnflaechen der Hecken hatten entartete UVs und zeigten Strahlenmuster.
- tools/plan-bilder.mjs zieht die Referenzfotos aus dem Plan-PDF.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-10 07:40:36 +02:00

11 KiB
Raw Blame History

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

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.

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.

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.

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 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.