Ein Dungeon Crawler in 20 Minuten: Browser-RPG mit Claude Code (Opus 4.8)

Veröffentlicht: 13. Juni 2026

Ich wollte eigentlich nur testen, wie weit man mit einem einzigen, bewusst vagen Prompt kommt. Das Ergebnis: ein vollständig spielbarer, browserbasierter Dungeon-Crawler — drei Klassen, fünf prozedural generierte Labyrinth-Level, Loot-System, Gegner-KI und ein Drachen-Boss am Ende. Entstanden in etwa 20 Minuten mit Claude Code und dem Modell Opus 4.8.

Kein Framework, keine Engine, kein Build-Step, keine einzige npm-Abhängigkeit. Reines Vanilla-JavaScript mit ES-Modulen und HTML5 Canvas. Man lädt einen Ordner, startet einen Mini-Webserver und spielt.

Der Prompt

Der Reiz lag in der Knappheit. Kein Lastenheft, keine Architektur-Vorgaben — nur eine Idee und der Verweis auf ein Genre:

Bitte erstelle eine Umsetzungsplanung für ein Javascript basiertes Rollenspiel in 2D in einer Top Down Ansicht für den Browser. Es soll Singleplayer mit einer Figur steuerbar sein über die Pfeiltasten und Aktionen wie Attack mit der Space Taste ermöglichen. Das Schema soll ähnlich dem Dungeon Crawler Genre aus den 1980er / 90er Jahren anmuten und eine ähnliche Mechanik haben. Gegner sollen Fantasy-Wesen sein wie Geister, Skelette, Mumien, Drachen, etc. Waffen sollen ein Schwert oder Bogen oder ein Zauberstab sein - je nach Charakter Klasse. Die Character Klasse kann man zum Spiel Beginn auswählen (Krieger, Magier, Archer). Das Level sollen labyrinth mäßig aufgebaut sein. Der Endgegner ist ein roter Drache - er ist schwerer zu besiegen als die vorherigen Gegner. Gegner droppen zufällige Items wie z. B. bessere Waffen, Rüstungen, Heiltränke oder Schätze / Geld.

Alles Weitere — die Klassenbalance, das Labyrinth-Verfahren, die Tile-Kollision, die Drop-Tabellen — hat Claude Code selbst entschieden und in einer sauber getrennten Modulstruktur umgesetzt.

Was in 20 Minuten entstand

Das fertige Spiel hat einen erstaunlich kompletten Funktionsumfang:

  • Drei Klassen mit eigenem Kampfstil und eigenen Werten
  • Fünf Labyrinth-Level mit steigender Schwierigkeit (Treppe = nächste Ebene)
  • Gegner-KI als Zustandsautomat: idle → chase → attack
  • Loot-System mit gewichteten Drop-Tabellen und Seltenheitsstufen
  • Inventar mit Ausrüsten/Benutzen und Klassenrestriktionen
  • XP & Level-Aufstieg mit skalierenden Werten
  • Boss-Kampf gegen den Roten Drachen im Finale

Die drei Klassen unterscheiden sich nicht nur kosmetisch:

KlasseWaffeKampfstil
KriegerSchwertNahkampf, viel HP
MagierZauberstabMagie-Fernkampf, verbraucht Mana
ArcherBogenSchneller Fernkampf

Gerendert wird alles über Emoji-Glyphen — 🤺 für den Krieger, 🐉 für den Roten Drachen, 👻 💀 🧟 für die Gegner. Eine pragmatische Designentscheidung, die ohne ein einziges Bild-Asset auskommt.

Die Architektur

Bemerkenswert war weniger, dass etwas Spielbares entstand, sondern wie sauber es strukturiert war. Statt einer 800-Zeilen-Datei kam eine nach Verantwortlichkeiten getrennte Modulstruktur heraus:

VerzeichnisAufgabe
engine/Game-Loop, Input, Renderer, Seeded-RNG, Asset-Mapping
world/Labyrinth-Generierung, Tilemap + Kollision, Kamera, Level
entities/Basisklasse, Spieler, Gegner, Projektile, Boden-Items
systems/Kampf, Loot, Inventar, Gegner-Spawn
data/Statische Definitionen: Klassen, Items, Gegnertypen
ui/HTML-Overlays: Menü, HUD, Inventar

Im Kern läuft eine Fixed-Timestep-Schleife mit 60 Hz und ein Zustandsautomat:

menu → playing ↔ inventory → gameover / victory

Das Labyrinth entsteht per Recursive-Backtracker-Algorithmus, die Zufälligkeit kommt aus einem seeded mulberry32-PRNG — das heißt, dieselbe Seed erzeugt dasselbe Dungeon. Die Level wachsen mit der Tiefe (MAZE_BASE = 8, plus Tiefenfaktor), und die Gegner werden tiefenskaliert platziert.

Ein gutes Beispiel für die Klarheit des generierten Codes ist die Eingabe-Abstraktion. Bewegung und Angriff lesen nie direkt Tasten ab, sondern fragen eine kleine Input-Fassade:

// Bewegungsvektor aus den Pfeiltasten
axis() {
  let x = 0, y = 0;
  if (down.has("ArrowLeft"))  x -= 1;
  if (down.has("ArrowRight")) x += 1;
  if (down.has("ArrowUp"))    y -= 1;
  if (down.has("ArrowDown"))  y += 1;
  return { x, y };
}

Diese eine Designentscheidung — Spiel-Logik gegen eine Input-Abstraktion statt gegen konkrete Tasten — sollte sich später als Glücksfall erweisen.

Und dann ging es weiter

Der eigentliche Mehrwert zeigte sich nicht im ersten Wurf, sondern in der iterativen Zusammenarbeit danach. Jede Erweiterung war ein kurzer Folge-Prompt, und durch die saubere Modulstruktur blieben die Eingriffe klein und lokal:

Touch-Steuerung fürs Handy. „Mach, dass es auch auf dem Handy funktioniert — Figur mit dem Finger ziehen, Aktionen per Doppel-Tipp." Weil die Spiel-Logik schon gegen die Input-Abstraktion lief, musste die eigentliche Spiel-Logik nicht angefasst werden. Ein neues touch.js-Modul übersetzt Finger-Gesten in genau dieselbe Schnittstelle: Drag-to-follow für die Bewegung, Doppel-Tipp für den Angriff, ein On-Screen-Button fürs Inventar.

Lokale Emoji-Schrift statt Geräte-Abhängigkeit. Emoji sehen auf jedem Betriebssystem anders aus — und auf alten Geräten fehlen sie teils ganz. Die Lösung: Googles Noto Color Emoji (SIL OFL 1.1) auf die ~19 tatsächlich genutzten Glyphen subsetten und lokal mitliefern. Aus 11 MB Schriftdatei wurden so 47 KB, eingebunden per @font-face — kein CDN, identische Darstellung überall.

SchrittVorherNachher
Emoji-QuelleSchrift des Gerätslokal gebündelt (47 KB)
Darstellungje nach OS andersüberall identisch
Externe Abhängigkeitimplizit (OS)keine

HUD-Umbau. Zuletzt wanderten die HP-, Mana- und Erfahrungs-Balken aus dem Canvas in eine eigene DOM-Seitenleiste links neben dem Spielfeld — damit die Anzeige das Geschehen nicht mehr überlappt.

Jede dieser Änderungen war ein Gespräch von wenigen Minuten, kein Refactoring-Marathon.

Fazit

Die 20 Minuten sind die griffige Zahl, aber sie sind nicht der eigentliche Punkt. Interessanter ist, dass aus einem absichtlich vagen Prompt kein Wegwerf-Prototyp wurde, sondern eine erweiterbare Codebasis — mit klaren Modulgrenzen, sinnvollen Abstraktionen und Konventionen, die spätere Änderungen billig machten.

Genau das ist der Unterschied zwischen „Code, der einmal läuft" und „Code, mit dem man weiterarbeiten kann". Ein gut gewählter erster Entwurf — saubere Trennung, eine Input-Fassade, austauschbare Render-Glyphen — verwandelt jeden Folge-Wunsch in einen kleinen, lokalen Eingriff statt in einen Umbau.

Und das Beste: Man kann es einfach spielen. Klasse wählen, los in den Kerker — der Drache wartet auf Ebene 5.

👉 Held des Drachenkerkers jetzt im Browser spielen

 Weitere Posts