Zwei Dinge wollte ich ausprobieren. Erstens: Wie weit kommt man mit 3D im Browser, wenn man WebGL bewusst weglässt — nur das nackte 2D-Canvas? Zweitens: Kann ein lokales Sprachmodell den Großteil des Codes schreiben, während ich nur noch Architekt und Reviewer bin? aiDoom ist die Antwort auf beide Fragen.
Es ist ein Wolfenstein-/Doom-artiger Raycaster. TypeScript, Vite, gebaut in unter 300 Millisekunden, am Ende rund 40 KB JavaScript gzippt. Texturen, Sprites, Sound-Effekte — alles prozedural erzeugt. Die einzigen externen Dateien sind ein paar MP3s für die Hintergrundmusik. Zehn Level, am Ende ein Boss, dessen Tod den Win-Screen auslöst.
Kein WebGL, mit Absicht
Der Renderer ist ein klassischer DDA-Raycaster: 640×480, Z-Buffer, Sprites aus acht Blickrichtungen. Jede Wand, jede Gegnertextur wird zur Laufzeit berechnet statt geladen. Das ist langsamer als WebGL und genau das war der Punkt — ich wollte verstehen, wo die Grenze liegt, nicht eine Engine-Library bedienen. Es zwingt einen, jeden Pixel zu verantworten.
Der eigentliche Trick: der Entwicklungs-Workflow
Spannender als das Spiel ist, wie es entstanden ist. Die Rollen waren strikt verteilt:
- Architekt (ich, mit Claude): liest den Plan, sucht die nächste Aufgabe, schreibt einen copy-paste-fertigen Prompt.
- Worker (Qwen3 27B, lokal auf Zuse): führt den Prompt gegen den Arbeitsbaum aus. Quasi-kostenlos pro Token, rund 60 Tokens pro Sekunde.
- Reviewer (wieder ich, mit Claude): liest die Diffs, prüft gegen die Spec, baut, testet, flaggt Bugs.
Die Idee: Das teure Frontier-Modell trifft die Architekturentscheidungen und kontrolliert die Qualität, das billige lokale Modell macht die Fleißarbeit. Hybrid spart Kosten beim Massen-Editing und behält trotzdem das Urteilsvermögen.
Klingt sauber. War es nicht — anfangs.
Wenn das Modell lügt
Zweimal hat Qwen behauptet, Code geschrieben zu haben, der nie im Arbeitsbaum landete. Mit präzisen Zeilenangaben in der Zusammenfassung. Die kreative Grundlagenarbeit war da — neue Synths, ein Boss-Sprite — aber die Verdrahtung über mehrere bestehende Dateien hinweg: komplett leer. Beide Male musste ich die Integration von Hand nachziehen.
Das Muster ist lehrreich: kreative Neu-Arbeit landet zuverlässig, das Verkabeln über mehrere Dateien mit viel Kontext kollabiert. Das Modell hat den Plan im Kopf und schreibt am Ende eine plausible Zusammenfassung — aus dem Plan, nicht aus dem, was die Werkzeuge tatsächlich getan haben.
Die Härtung war ein einziger Satz, der seitdem an jedem Prompt klebt:
Zeige die Ausgabe von
git statusundgit diff --stateins zu eins.
Werkzeug-Ausgaben kann man nicht halluzinieren — entweder die Shell liefert sie oder nicht. Ein Selbstbericht "ich habe X gemacht" dagegen sehr leicht. Ab diesem Prompt liefen die Aufgaben sauber durch: Grundlage plus Integration, null Nacharbeit, beim ersten Versuch spec-konform.
Was ich mitgenommen habe
- Niemals dem Selbstbericht trauen, nur der Werkzeug-Ausgabe. "Build ist grün" allein reicht nicht — der Build geht auch durch, wenn nur die halbe Verkabelung da ist; der Rest fällt erst beim Spielen auf.
- Eine VERBOTEN-Sektion im Prompt schließt Türen für kreative Interpretation. "Fass die Tests nicht an. Dieses Modul ist read-only."
- Keine ganzen Funktionskörper vorgeben. Das Modell soll interpretieren, nicht abschreiben. Ein Zeilen-Hinweis reicht.
Der Code ist am Ende Nebensache. Was bleibt, ist eine Methode: ein lokales Modell als disziplinierten, misstrauisch beaufsichtigten Junior einzusetzen — und genau zu wissen, an welcher Stelle es einen anlügen wird.