diff --git a/Dockerfile b/Dockerfile
index 046bd4c..c2b9248 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -8,5 +8,5 @@ COPY public/ ./
# If the site references additional resources, copy them too
COPY resources/ ./resources
-# Optional: provide your own nginx.conf for SPA routing
-# COPY nginx.conf /etc/nginx/conf.d/default.conf
\ No newline at end of file
+# Provide custom nginx.conf for clean URLs
+COPY nginx.conf /etc/nginx/conf.d/default.conf
\ No newline at end of file
diff --git a/README.md b/README.md
index 26b1a2a..6dd3354 100644
--- a/README.md
+++ b/README.md
@@ -62,7 +62,20 @@ python main.py
Output files will be generated in the current directory as PNG images.
## Available Diagrams
+# Network Topology Viewer
+A modern, interactive network topology visualization tool built with D2 diagrams.
+
+## Features
+
+- Interactive network diagram with pan/zoom
+- Real-time node details and tooltips
+- Clean, modern UI with dark theme
+- Export capabilities
+
+## Running with Docker
+
+Build and run:
- `lan_architecture.py` - Home Lab / Auction Stack Architecture diagram
- `main.py` - Network architecture diagram
diff --git a/nginx.conf b/nginx.conf
new file mode 100644
index 0000000..c607e7b
--- /dev/null
+++ b/nginx.conf
@@ -0,0 +1,22 @@
+server {
+ listen 80;
+ server_name localhost;
+ root /usr/share/nginx/html;
+ index index.html;
+
+ # Enable clean URLs without .html extension
+ location / {
+ # Try the exact URI, then with .html, then as directory with index.html, then 404
+ try_files $uri $uri.html $uri/ =404;
+ }
+
+ # Optional: Redirect .html URLs to clean URLs
+ if ($request_uri ~ ^/(.*)\.html(\?|$)) {
+ return 301 /$1$2;
+ }
+
+ # Gzip compression for better performance
+ gzip on;
+ gzip_vary on;
+ gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
+}
diff --git a/public/d2.html b/public/d2.html
new file mode 100644
index 0000000..014e5ca
--- /dev/null
+++ b/public/d2.html
@@ -0,0 +1,993 @@
+
+
+
+
+
+ Interactive Network Topology - D2
+
+
+
+
+
+
+
+
Loading D2 runtime...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/network.d2 b/public/network.d2
new file mode 100644
index 0000000..4b35c90
--- /dev/null
+++ b/public/network.d2
@@ -0,0 +1,151 @@
+title: Home Network Topology | font-size: 24
+
+classes: {
+ router: {
+ style: {
+ fill: "#f59e0b"
+ stroke: "#fbbf24"
+ stroke-width: 2
+ shape: rectangle
+ border-radius: 5
+ }
+ }
+ core: {
+ style: {
+ fill: "#ef4444"
+ stroke: "#f87171"
+ stroke-width: 2
+ shape: hexagon
+ }
+ }
+ infra: {
+ style: {
+ fill: "#10b981"
+ stroke: "#34d399"
+ stroke-width: 2
+ }
+ }
+ worker: {
+ style: {
+ fill: "#8b5cf6"
+ stroke: "#a78bfa"
+ stroke-width: 2
+ shape: hexagon
+ }
+ }
+ iot: {
+ style: {
+ fill: "#f97316"
+ stroke: "#fb923c"
+ stroke-width: 2
+ shape: rounded-box
+ }
+ }
+ client: {
+ style: {
+ fill: "#6b7280"
+ stroke: "#9ca3af"
+ stroke-width: 2
+ shape: rectangle
+ border-radius: 5
+ }
+ }
+ dns: {
+ style: {
+ fill: "#0ea5e9"
+ stroke: "#38bdf8"
+ stroke-width: 2
+ }
+ }
+}
+
+Internet: "☁️ Internet\nCloudflare DNS\n5.132.33.195" {
+ class: dns
+ near: top-center
+}
+
+Router: "🛜 Zyxel Router\nhub.lan\n192.168.1.1" {
+ class: router
+ near: Router.n
+}
+
+LAN: {
+ label: "LAN 192.168.1.0/24"
+ shape: rectangle
+ style: {
+ fill: "#1e293b"
+ stroke: "#475569"
+ stroke-width: 2
+ stroke-dash: 5
+ opacity: 0.3
+ }
+
+ Traefik: "⚡ Traefik\nReverse Proxy\n192.168.1.159" {class: core}
+ Dokku: "⚡ Dokku PaaS\n192.168.1.159" {class: core}
+ Gitea: "⚡ Gitea\ngit.appmodel.nl" {class: core}
+ Auction: "⚡ Auction\nauction.appmodel.nl" {class: core}
+ MI50: "⚡ MI50/Ollama\nollama.lan" {class: core}
+
+ AdGuard: "🔧 AdGuard\nDNS Filter" {class: infra}
+ XU4: "🔧 XU4 DNS\n192.168.1.163" {class: infra}
+ C2: "🔧 C2 DNS\n192.168.1.227" {class: infra}
+ HA: "🔧 Home Assistant\n192.168.1.193" {class: infra}
+
+ Atlas: "💻 Atlas\n192.168.1.100" {class: worker}
+
+ TV: "📺 Kamer-TV\n192.168.1.240" {class: iot}
+ Hue: "💡 Philips Hue\n192.168.1.49" {class: iot}
+ Eufy: "📹 Eufy S380HB\n192.168.1.59" {class: iot}
+ IoT: "🔌 IoT Devices\nNest/Roborock/ESP/Printer" {class: iot}
+
+ MIKE: "💻 MIKE PC\n192.168.1.100\nLAN + Tether" {class: client}
+ Lotte: "📱 Lotte\n192.168.1.133" {class: client}
+}
+
+Tether: {
+ label: "Tether 192.168.137.0/24"
+ shape: rectangle
+ style: {
+ fill: "#0f172a"
+ stroke: "#334155"
+ stroke-width: 2
+ stroke-dash: 5
+ opacity: 0.3
+ }
+
+ Hermes: "💻 Hermes\n192.168.137.239" {class: worker}
+ Plato: "💻 Plato\n192.168.137.239\nllm.plato.lan" {class: worker}
+}
+
+Internet -> Router: provides DNS
+
+Router -> LAN.Traefik: routes
+Router -> LAN.Dokku: routes
+Router -> LAN.Gitea: routes
+Router -> LAN.Auction: routes
+Router -> LAN.MI50: routes
+Router -> LAN.AdGuard: routes
+Router -> LAN.XU4: routes
+Router -> LAN.C2: routes
+Router -> LAN.HA: routes
+Router -> LAN.Atlas: routes
+Router -> LAN.TV: routes
+Router -> LAN.Hue: routes
+Router -> LAN.Eufy: routes
+Router -> LAN.IoT: routes
+Router -> LAN.MIKE: routes
+Router -> LAN.Lotte: routes
+
+LAN.MIKE -> Tether.Hermes: tether bridge
+LAN.MIKE -> Tether.Plato: tether bridge
+
+LAN.Traefik -> LAN.Gitea: proxies
+LAN.Traefik -> LAN.Dokku: proxies
+LAN.Traefik -> LAN.Auction: proxies
+
+LAN.XU4 -.-> LAN.AdGuard: filters
+LAN.C2 -.-> LAN.AdGuard: filters
+LAN.Atlas -.-> LAN.AdGuard: uses
+LAN.HA -.-> LAN.AdGuard: uses
+Tether.Hermes -.-> LAN.AdGuard: uses
+Tether.Plato -.-> LAN.AdGuard: uses
\ No newline at end of file
diff --git a/public/struz.html b/public/struz.html
new file mode 100644
index 0000000..928b207
--- /dev/null
+++ b/public/struz.html
@@ -0,0 +1,1295 @@
+
+
+
+
+
+ Structurizr Network Topology
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/public/top.html b/public/top.html
new file mode 100644
index 0000000..ef1b514
--- /dev/null
+++ b/public/top.html
@@ -0,0 +1,933 @@
+
+
+
+
+
+ Interactive Network Topology
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file