No description
Find a file
Tronax ef75203db7
feat(duel): allow swapping main view to opponent's board
- Add a toggle on the picture-in-picture window to swap the big board
  with the mini view of the opponent's field
- Color-coded frame and badge identify whose board is currently shown
  (blue = player 1, orange = player 2)
- Block building and rushing while spectating the opponent's board;
  the PiP then shows your own field instead
- Clarify duel-mode descriptions in lobby and start screen, add hints
  in the multiplayer bar
- Replace previous announcement banners so only one shows at a time
2026-08-16 13:35:46 +02:00
scripts feat(server): add security hardening for public hosting 2026-08-16 13:16:20 +02:00
server feat(server): add security hardening for public hosting 2026-08-16 13:16:20 +02:00
src feat(duel): allow swapping main view to opponent's board 2026-08-16 13:35:46 +02:00
.dockerignore feat(docker): add self-hosted all-in-one container setup 2026-08-16 12:15:52 +02:00
.gitignore feat: initialize TRXTD browser tower defense 2026-08-15 16:07:09 +02:00
docker-compose.yml feat(docker): add self-hosted all-in-one container setup 2026-08-16 12:15:52 +02:00
Dockerfile feat(docker): add self-hosted all-in-one container setup 2026-08-16 12:15:52 +02:00
index.html feat: initialize TRXTD browser tower defense 2026-08-15 16:07:09 +02:00
package-lock.json feat: initialize TRXTD browser tower defense 2026-08-15 16:07:09 +02:00
package.json feat: initialize TRXTD browser tower defense 2026-08-15 16:07:09 +02:00
README.md feat(server): add security hardening for public hosting 2026-08-16 13:16:20 +02:00
tsconfig.json feat: initialize TRXTD browser tower defense 2026-08-15 16:07:09 +02:00
vite.config.ts feat: initialize TRXTD browser tower defense 2026-08-15 16:07:09 +02:00

TRXTD Tower Defense im Browser

Ein vollständiges Tower-Defense-Spiel, gebaut mit Vue 3 + TypeScript + Vite. Die Spiellogik läuft in reinem TypeScript auf einem HTML-Canvas (60 FPS), Vue kümmert sich um HUD, Menüs und Panels.

Enthält Solo-Kampagne, 2-Spieler-Coop und 1v1-Duell (Online/Lokal per WebSocket).

Schnellstart

  1. Abhängigkeiten installieren:

    npm install
    
  2. Frontend (Vite) und Multiplayer-Server starten:

    # Terminal 1: Dev-Server
    npm run dev        # → http://localhost:5173
    
    # Terminal 2: Multiplayer-Relay (nur für Coop / 1v1 nötig)
    npm run server     # → ws://localhost:3001
    
  3. Browser öffnen unter http://localhost:5173.


🐳 Docker

Das Spiel gibt es als All-in-One-Container: Frontend (statisch) und Multiplayer-Server teilen sich einen Port ideal für Self-Hosting.

# Image bauen (Multi-Stage-Build: Build → schlankes Runtime-Image)
docker build -t trxtd:latest .

# Container starten
docker run -d --name trxtd -p 3001:3001 trxtd:latest

# Oder mit Docker Compose (empfohlen)
docker compose up -d

Danach läuft das komplette Spiel inkl. Online-Multiplayer unter http://localhost:3001.

Enthaltene Härtung:

  • Multi-Stage-Build (kein Build-Tooling im Runtime-Image)
  • Läuft als unprivilegierter Nutzer (node)
  • HEALTHCHECK über /health
  • /assets/ mit immutablen Cache-Headern, SPA-Fallback für alle anderen Routen
  • WebSocket-Sicherheit: Payload-Limit (4 KB), Rate-Limiting (30 Aktionen/s), Schema-Validierung, Ping/Pong-Heartbeat

Nützliche Umgebungsvariablen:

Variable Default Bedeutung
PORT 3001 HTTP- und WebSocket-Port
DIST_DIR ./dist Ordner mit den statischen Dateien
ALLOWED_ORIGINS Zusätzlich erlaubte WebSocket-Origins (Komma-Liste, z. B. https://spiel.example.com)

Öffentliches Hosting hinter Reverse Proxy (Nginx Proxy Manager / NPMplus):

  1. Container nur im internen Netz erreichbar machen (Port 3001 nicht am Router freigeben!), z. B.:
    # docker-compose.yml — gemeinsames Netzwerk mit dem Proxy
    services:
      trxtd:
        build: .
        restart: unless-stopped
        expose: ["3001"]          # intern, kein ports:-Mapping nach außen
      # networks: proxy_net ...
    
  2. In NPM/NPMplus einen Proxy Host anlegen:
    • Domain: spiel.example.com (DNS-A-Record auf den Server)
    • Scheme: http · Forward Hostname: Containername (gemeinsames Docker-Netz) oder Server-LAN-IP · Port: 3001
    • Websockets Support: ✔ aktivieren (zwingend erforderlich für Multiplayer!)
    • Block Common Exploits: ✔ · Cache Assets: ✘ (der Server setzt eigene Cache-Header)
    • SSL-Tab: Let's-Encrypt-Zertifikat anfordern, Force SSL + HTTP/2 aktivieren
  3. Fertig das Spiel (inkl. Coop/1v1 über wss://) läuft unter https://spiel.example.com.

Serverseitige Härtung (aktiv): CSP-/Frame-/Referrer-Header · Origin-Check gegen Cross-Site-WebSocket-Hijacking · X-Forwarded-For-Auswertung nur aus privaten Proxy-Netzen · max. 500 WebSocket-Verbindungen total / 20 pro IP · max. 300 Räume · Payload-Limit 4 KB · Rate-Limit 30 Aktionen/s · Schema-Validierung · Ping/Pong-Heartbeat · Raum-Timeout 30 min.

Manuell ohne Docker im Produktionsmodus starten:

npm run build
npm run server   # serves dist/ + ws auf :3001

Spielmodi

1. Solo-Kampagne

Verteidige deine Basis gegen 20 handgetunte Wellen (Leicht: 30 Leben, Normal: 20 Leben, Schwer: 12 Leben). Nach Welle 20 geht es auf Wunsch im Endlos-Modus weiter.

2. 🤝 2-Spieler-Coop

  • Gemeinsame Basis & gemeinsames Gold Sprecht euch ab!
  • Eigene Türme: Deine Türme haben einen blauen Ring, die deines Partners einen orangenen Ring (jeder kann nur seine eigenen Türme upgraden oder verkaufen).
  • Gegner haben 70 % mehr Leben, um der doppelten Feuerkraft standzuhalten.
  • Wellen starten automatisch nach Countdown oder per Klick auf „Nächste Welle" (beide können klicken).

3. ⚔ 1v1-Duell (Tower-Battles-Prinzip)

  • Jeder Spieler verteidigt sein eigenes Spielfeld.
  • Über ein Live-Miniaturfenster (PiP) siehst du in Echtzeit das Spielfeld deines Gegners mit allen Türmen und Gegnern.
  • Rush-Mechanik: Schicke gegen Gold (60 🪙 + 8 🪙/Welle) eine Welle schneller Läufer auf die Basis des Gegners!
  • Siegbedingungen:
    • Basis des Gegners fällt auf 0 Leben → Sofortsieg!
    • Nach 20 Wellen gewinnt, wer mehr Leben übrig hat (bei Gleichstand entscheiden die Punkte).

Multiplayer-Raum-System

  • Klicke auf dem Startbildschirm auf „Coop-Raum erstellen" oder „1v1-Raum erstellen".
  • Gib deinem Mitspieler den 4-stelligen Raum-Code (z. B. 5SK7).
  • Der Mitspieler tippt seinen Namen + den Code ein und klickt auf „Beitreten".
  • Der Host startet das Spiel, sobald beide in der Lobby sind.
  • Funktioniert im lokalen Netzwerk (LAN / WLAN) für Freunde über das Internet einfach Port 3001 freigeben oder über ngrok/Tailscale leiten.

Türme

Turm Kosten Upgrade 2/3 Besonderheit
🏹 Bogenturm 50 🪙 60 / 110 🪙 Günstig, schnelle Einzelschüsse, trifft Luft
🧨 Kanone 110 🪙 100 / 180 🪙 Flächenschaden, trifft keine Flieger
❄️ Eisturm 80 🪙 70 / 130 🪙 Verlangsamt alle Gegner im Umkreis um bis zu 65 %
Teslaturm 130 🪙 120 / 200 🪙 Kettenblitz springt auf bis zu 5 Gegner über
💫 Laserturm 160 🪙 150 / 260 🪙 Soforttreffer, maximale Reichweite & Durchschlag
  • Verkauf: 70 % der Gesamtinvestition (Kauf + Upgrades) werden erstattet.
  • Zielmodi: Erster / Letzter / Stärkster / Nächster.

Gegner

  • 🟢 Kriecher: Standard-Einheit, gut für frühes Gold
  • 🟡 Läufer: Sehr schnell Bogentürme oder Eisturm nötig
  • Panzer: Zäh, kostet 2 Leben bei Durchbruch
  • 🟣 Flieger: Ignorieren den Weg und fliegen auf halber Höhe geradeaus (nur Bogenturm, Eisturm, Tesla, Laser!)
  • 🔴 Boss: Riesige Lebensleiste, kostet 5 Leben (Wellen 10, 15, 20 …)

Hindernisse

Bäume (60 🪙) und Felsen (40 🪙) blockieren strategisch wichtige Bauplätze.

  • Klick auf das Hindernis → „⛏ Entfernen" öffnet sich oben rechts.
  • Nach dem Entfernen wird das Feld sofort bebaubar.

Steuerung

  • 15 Turm zum Bauen auswählen, Klick auf freies Feld platziert ihn
  • Klick auf Turm Details, Upgrade, Verkauf, Zielmodus
  • Klick auf Hindernis Entfernen gegen Gold
  • Leertaste nächste Welle früh starten (Frühstart-Bonus!) / Pause (nur Solo)
  • U Upgrade · V Verkaufen · T Zielmodus wechseln
  • P Pause (nur Solo) · M Ton an/aus · Esc Abbrechen
  • Rechte Maustaste Bauauswahl aufheben

Technische Details

  • Client-Side Simulation: Determinister Lockstep-Tick-Loop (30 Hz) beide Clients berechnen den exakten Spielverlauf parallel; der Server (server/server.mjs) vermittelt nur die Räume und leitet Aktionen weiter (minimaler Traffic, kein Lag bei der Bewegung).
  • Renderer: Offscreen-gepufferter HTML-Canvas mit dynamischer Vollbild-Skalierung, Retina-DPR-Support, Partikelsystem und Mündungsfeuer.
  • Sound: Web Audio API mit synthetisierten Klängen (keine externen Audio-Dateien).
  • Automatisierte Tests:
    • npm run sim Headless-Bot spielt die Solo-Kampagne zur Balancing-Prüfung durch
    • npx tsx scripts/test-mp.mts Lockstep-Determinismus-Test (3600 Ticks, byte-identischer Zustand auf beiden Seiten)
    • npx tsx scripts/test-obstacle.mts Feature-Test: Hindernis-Entfernung