Software

3D-OpenStreetMap-Karten aus dem 3D Drucker

KI-Modelle, die bei der Softwareentwicklung unterstützen, haben sich in den letzten 5 Jahren deutlich verbessert. Anfangs generierten sie selten mehr als vier fehlerfreie Codezeilen. Zum Entstehungszeitpunkt des Artikels arbeiten KI-Agenten stundenlang selbstständig Implementierungspläne ab und produzieren tausende Zeilen Code ohne Syntaxfehler.

Im Laufe der Jahre 2024 und 2025 wurden KI-CLI-Agenten (KI Programmier-Agenten, die über ein Terminal Interface gesteuert werden) immer populärer. Anfang 2025 wuchs schließlich auch meine Neugier so sehr, dass ich das Anthropic Abo für Claude Code abgeschlossen habe. Ich beschloss, das oberste Projekt von meinem Projektideen-Stapel umzusetzen: Eine Webseite, die aus OSM-Daten 3D Modelle für den 3D Drucker erzeugt.

Es gibt einige Webseiten für diesen Zweck, doch die Benutzerfreundlichkeit existierender Lösungen lässt viele Wünsche offen, und sie sind oft auf ein serverseitiges Backend für die eigentliche Datenverarbeitung angewiesen.

Bei unserer Anwendung soll die gesamte Datenverarbeitung vollständig im Browser erfolgen. Die Benutzeroberfläche sollte an das alte Computerspiel populos  angelehnt sein. Da der Fokus aber primär auf der Funktionalität lag, wurde diese Anforderung nicht sehr streng verfolgt.

Das beschriebene Projekt wurde über den Zeitraum von einem Jahr mit verschiedenen KI-Modellen umgesetzt, unter anderem Claude Sonnet 3.7 - 4.6, Claude Opus 4.5 - 4.6, OpenAI Codex und ChatGPT.

Datenquellen

Als Technologien für die Datenquellen sind OpenMapTiles OSM Vector-Tiles und ein Raster-DGM im Mapbox Terrain-RGB Format vorgesehen. Die Vector-Tiles bieten bereits generalisierte Geometrien für die stilisierte Darstellung von Gebäude, Straßen und verschiedenen Geländearten.

Technologie

Neben den Spezifikationen für die Datenformate wird auch eine Liste von NPM-Paketen vorgegeben. NPM-Pakete sind wiederverwendbare Code-Bibliotheken oder Tools, die über den Node Package Manager (NPM) verwaltet und in JavaScript/Node.js-Projekten als Abhängigkeiten installiert werden können. @mapcomponents/react-maplibre wird für die 2D-Kartendarstellung verwendet, weil es mit den verwendeten Datenformaten kompatibel ist und sich hervorragend für die benutzerfreundliche Auswahl des Kartenausschnitts auf einer 2D Karte eignet. Ferner wird Three.js, für die Darstellung des 3D-Modells und Unterstützung von Exportfunktionen eingesetzt.

Das 3D-Modell

Die Basis-Geländeplatte muss über ausreichend viele Punkte verfügen, damit das Geländemodell gut abgebildet werden kann und die Verarbeitung nicht zu aufwändig wird. Anschließend müssen die Kacheln vom Digitalen Geländemodell geladen werden, die eine Schnittmenge mit dem ausgewählten Kartenausschnitt haben und für jeden Punkt die Z-Koordinate (in three.js Y) auf die abgelesene Höhe aus dem Geländemodell angepasst werden. Anschließend erfolgt die Abbildung der verschiedenen Ebenen. Da Polygone als plane Flächen nicht mit dem 3D-Drucker ausgedruckt werden können, werden sie zur Volumenbildung entlang der Z-Achse extrudiert. Dieses Vorgehen ist vom 'fill-extrusion'-Ebenentyp der MapLibre Style Spezifikation inspiriert. Damit das 3D-Modell zur Basis- Geländeplatte passt, wird die Anzahl der Punkte erhöht, und für jeden Punkt der Z-Werte auf den passenden Wert aus dem Geländemodell angepasst. Line-String Geometrien werden mit einer Buffer-Funktion in Polygone umgewandelt und anschließend mit vorhandener Logik für Polygone verarbeitet.

Vorgehen

Zuerst wird ein ausführlicher Implementierungsplan für die Umsetzung erstellt. Das kann auch außerhalb des CLI coding Agenten, z.B. im ChatGPT-, Anthropic- oder Gemini-Chat-Webinterface passieren. Wir übergeben dem Chat alle technischen Details und bitten ihn, einen detaillierten Plan zu erstellen. Falls darin etwas nicht den architektonischen Vorstellungen entspricht, ist jetzt ein guter Zeitpunkt Änderungen vorzunehmen.

Anschließend wird der Plan an Claude Code übergeben, der daraus eine Liste mit Aufgaben übernimmt, sofort loslegt und für die nächsten 30 Minuten beschäftigt ist. Zwischendurch werden Fragen gestellt, die Entwicklungsumgebung darf der KI-Agent nach eigenem Ermessen starten. Bei anderen Aktionen, z.B. dem Löschen und Abrufen von Webseiten, soll erst um Erlaubnis gefragt werden.

Bei der Initialisierung des Projekts fällt noch auf, dass das React Projekt zuerst mit create-react-app erstellt wurde, was schon seit 2022 nicht mehr gewartet wurde. Es musste also explizit darum gebeten werden das Projekt mit vite und dem react+typescript Template zu erstellen. Neuere KI-Modelle beginnen direkt mit vite oder produzieren eine ähnliche Entwicklungsumgebung und Build Konfiguration von selbst. Nachdem die Entwicklungsumgebung steht, wird Claude gebeten sie zu starten, damit Syntax- oder Kompilierungsfehler direkt im KI-Kontext landen und der Mensch als Überbringer von Log-Meldungen aus der Feedback-Schleife entfernt wird.

Die erste Version

Wir starten mit einer MapComponents-maplibre-gl-Karte, auf der mit dem BBox-Selector Component eine Bounding-Box ausgewählt werden kann. Unten links befindet sich ein kleines Formular für die Erstellung des 3D-Modells. Sobald die Berechnung abgeschlossen ist, wird das 3D Model mit three.js in einem Pop-up-Fenster dargestellt. 

Abb. 1: 23.03.2025 - Auswahl der Bounding-Box auf der MapComponents-Karte
Abb. 2: 23.03.2025 - Vorschau des 3D-Geländes in three.js - https://github.com/cioddi/stlmaps/commit/d7cd03b86d7bdc75c7b1767d300be4bd4138fd49
Einer der ersten Testdrucke. Es ist ein besonderer Moment, wenn man nach längerer Vorbereitung die ersten gedruckten Ergebnisse in den Händen hält.

Die Entwicklung schreitet schnell voran - von dem Abruf der nötigen DGM Tiles, über Abruf und Lesen der Vector-Tiles und dem Filtern bestimmter Features daraus, bis hin zur Erzeugung der 3D-Meshes für Gebäude und gebufferte LineString-Geometrien.

In dem Chat-Interface des Coding Agenten werden in einer Konversation die Implementierungsdetails geklärt, auf aussichtslose Ansätze hingewiesen, zwischendurch viel recherchiert und dabei Code produziert, der die gewünschte Funktionalität bereitstellt.

Je höher die Geschwindigkeit, desto schneller verliert man die Übersicht über den Code. Die Anhäufung von Fallback-Lösungen sorgte zwar dafür, dass die Anwendung ohne Fehler in der Konsole lief, machte aber den resultierenden Code extrem unübersichtlich. Es war kaum mehr nachvollziehbar, welche Logik schlussendlich ausgeführt wurde. Jedes Mal, wenn irgendwo ein Problem auftrat, wurde eine Fallback Lösung erstellt. Nachdem der Code wieder ein wenig aufgeräumt war, konnte es weitergehen. Hier ist etwas Disziplin gefragt, denn im Gegensatz zum Aufräumen, das im Frontend keine sichtbaren Veränderungen bringt, liefert die Umsetzung neuer Features alle paar Minuten ein spürbares Gefühl von Erfolg und Befriedigung.

Abb. 4: 30.05.2025 - https://github.com/cioddi/stlmaps/commit/7f49c555b66e8b3dbafb658cfb68f8bf3c463224

Bei der Durchsicht des Codes fällt auch die Neigung der KI auf, immer neue Typen zu definieren, die sich teilweise nur in wenigen Eigenschaften unterscheiden. Mit der MaplibreStyle-Layer-Spezifikation können mit den umfassenden Filtermöglichkeiten bereits fast alle nötigen Informationen für unsere Zwecke beschrieben werden. Darauf aufbauend definieren wir einen Datentyp für die Beschreibung der Konfiguration unserer Ebenen, der in der gesamten Anwendung genutzt werden soll

Abb. 5: 13.04.2025 - Das neue Datenmodell für die Beschreibung der Ebenen ist links im Konfigurations-Formular abgebildet - https://github.com/cioddi/stlmaps/commit/3d44cc433624221c99ddf811951ebaedfeba4bf0

Die Entscheidung für das einheitliche Datenmodell ermöglicht es, auch die Einfärbung und Sichtbarkeit der Karten-Ebenen auf der MapComponents-Karte mithilfe des MlVectorTileLayers und einer dynamisch erzeugten Style-JSON Datenstruktur, immer synchron mit der Konfiguration zu halten.

Eine einfache Städtesuche, basierend auf einer JSON-Datei, ist ebenfalls schnell hinzugefügt. (Eine Übergangslösung, die in einer späteren Version mit einem Cloud-optimierten Datenbankformat umgesetzt werden soll.)

Die Rust Version

Da ich mit der Geschwindigkeit noch nicht zufrieden war und bei der Arbeit erste Erfahrungen mit WebAssembly sammeln konnte, beschloss ich, einen Teil der Anwendung in Rust umschreiben zu lassen. Das Repository, bereits ein pnpm-Monorepo, wurde um ein neues Package erweitert, das den Rust Code enthalten sollte. Die Einrichtung hat Claude so gut umgesetzt, dass es sich perfekt in die vorhandene Konfiguration für Build und Entwicklungsumgebung (inkl. live-reload) einfügt.

Beim Erzeugen des Rust Codes wird deutlich, dass die KI Typescript besser generiert als Rust. Es werden deutlich mehr Fehler gemacht. Das GeoRust Ökosystem ist noch nicht ganz ausgereift. Nachdem Stück für Stück eine Funktionalität nach der anderen nach Rust portiert war, stieß ich bei den Line-String Geometrien auf ein Problem. Das Problem war, dass ich für den LineString-Buffer eine Funktion aus einer neueren Version des iOverlay crates (einer Rust Bibliothek für Boolesche Operationen auf 2D Geometrien) benötigte, welches noch nicht mit den anderen verwendeten Abhängigkeiten kompatibel war. Es ist mir auch nicht gelungen, mit Hilfe von Claude oder Codex die fehlende Funktion zu implementieren. Es wurden viele vermeintliche Lösungen produziert, die aber immer an bestimmten Fällen scheiterten. Die Übergangslösung war ein lokaler iOverlay Fork mit anderem Namen, nicht schön, aber auch nicht dauerhaft. Da es sich um ein Abhängigkeitsproblem handelt, wusste ich, dass es sich mit der Zeit selbst lösen würde.

Claude Opus 4.5

Am 24.11.2025 erschien Claude Opus. Das neue KI-Modell hatte bei mir schon einmal eine Lösung für ein Problem gefunden, bei dem Sonnet 4.5 und Codex oder GPT sich nur im Kreis drehten. Die aktuellen Export Möglichkeiten obj und stl exportierten ein 3D-Mesh. Beim GLTF/GLB Export bleiben die einzelnen Layer-Meshes erhalten und können direkt in der Slicer Software des 3D-Druckers in der gewünschten Farbe eingefärbt werden, ohne dass mühsam und unsauber die Flächen mit dem Pinsel-Werkzeug eingefärbt werden müssen. Da die slicer Software aber keine GLTF-Dateien unterstützt, müssen die Modelle erst ins 3MF-Format konvertiert werden. Da das Format noch nicht sehr verbreitet war, gab es keine Libraries auf NPM oder crates.io für den 3mf Export.

Ich beschloss, es mit der one-shot Methode zu probieren und gab Claude die 3mf Spezifikation in den Kontext mit und schrieb: "Add 3mf export Button next to the existing export buttons. See the spec for technical details."

Die Aufgabe, an der ältere KI-Modelle gescheitert waren, erledigte Claude Opus in zwei Versuchen. Ein neuer Export-Button wurde neben den vorhandenen eingerichtet. Dieser initiierte nach kurzer Zeit den Download einer 3mf Datei, die sich direkt in der Bambulabs Slicer Software (Bambu Studio) importieren ließ. Der Versuch verdeutlicht, dass auch Opus an Grenzen stößt.

Ein noch bestehendes Problem ist auf den Fotos gut sichtbar: Mindestmaße der Geometrien müssen eingehalten werden, damit der 3D-Drucker sie sauber ausdrucken kann. Eine zu geringe Höhe führt dazu, dass Geometrien nicht vollständig gedruckt werden.

Abb. 8: Das Export Modul inklusive des hinzugefügten 3MF Export-Buttons
Abb. 9 & 10: Fertige Ausdrucke

Fazit

Fortschritte, die KI-Coding-Agenten in den letzten Jahren gemacht haben, sind auch für die schärfsten Kritiker nicht mehr zu leugnen. Bestehende Unzulänglichkeiten sind jedoch weiterhin vorhanden. Gerade das Beispiel des Abhängigkeitsproblems bei Rust ist hierfür ein deutliches Zeichen. Die Weiterentwicklung und Verbreitung der Nutzung sind unaufhaltsam. Aus meiner Sicht ist positiv, dass Software-Entwickler*innen die Möglichkeit haben, eigene Projektideen umzusetzen. Der Code ist eventuell nicht schön und die Architektur nicht perfekt, aber es bietet eine Funktionalität, die genau den eigenen Vorstellungen entspricht. In diesem Fall eine Webseite, die ein 3D-Modell aus einem Kartenausschnitt erstellt, das ein paar Stunden später als physisches Objekt in den Händen gehalten werden kann. Individuelle Bedürfnisse an die Funktionalität von Software könnten durch KI-generierte individuelle Lösungen in Zukunft noch besser bedient werden. Die Entwicklung von stlmaps zeigt, dass hier ein solides Fundament aus erprobter Open-Source-Software und verbreiteten Spezifikationen die Arbeit deutlich erleichtern.

Die Anwendung zum Ausprobieren und Selbstdrucken finden Sie hier.

Disclaimer: Die in diesem Blogartikel beschriebene Vorgehensweise sowie die erzielten Ergebnisse sind ausschließlich Teil eines individuellen Experiments zur KI-unterstützten Softwareentwicklung und repräsentieren nicht die offiziellen Softwareentwicklungsprozesse der WhereGroup.

Über den Autor

Steckbrief

Tobias Weber ist seit Januar 2021 Software Entwickler bei der WhereGroup GmbH in Bonn. Als Full-Stack Developer hat er in den letzten 15 Jahren in diversen Projekten mit verschiedenen Technologien wie Javascript, React, Vue.js, Docker, PHP, ExtJS, MySQL, Three.js gearbeitet. In der letzten Zeit standen bei ihm React und Django im Vordergrund.

Tobias Weber WhereGroup