Zum Inhalt springen
Zurück zum Portfolio

Top Shot Reloaded — 1v1-Speedball-Duell

Ein Paintball-Duell fürs Smartphone, allein vom Prototyp bis zur Beta gebaut: deterministische Headless-Simulation mit 120 Hz, WebGL-Renderer, druckinspiriertes Designsystem, Lockstep-Multiplayer über ein Cloudflare-Relay und native Shells für iOS, Android und Desktop.

Titelbildschirm, ein laufendes Duell und das HIT!-Verdict — unbearbeitete Aufnahmen aus dem aktuellen Beta-Build.

Überblick

Top Shot Reloaded ist ein Eins-gegen-eins-Speedball-Duell aus der Vogelperspektive: zwei Spieler, zwei gespiegelte aufblasbare Bunker, 45 Sekunden auf der Uhr und die Frage, wann man heraustritt und schießt. Seit Juni 2026 baue ich es allein — als Designer, Entwickler und derjenige, der die Release Notes schreibt. TypeScript und Vite im Web, verpackt mit Capacitor für iOS und Android und Tauri 2 für macOS und Windows.

Titelbildschirm, Practice-Setup und Clinic — die ruhige „Paper“-Ebene des Spiels

Die Kernidee: Die Position ist der Abzug

Kein Munitionszähler, keine Feuerrate zu verwalten. Jeder Bunker hat feste Positionen — linke Bahn, rechte Bahn, vorne über die Kante, hinten in tiefer Deckung — und jede Position hat zwei Zustände: eingezogen und still, oder herausgetreten mit laufendem Markierer. FIRE halten tritt heraus, loslassen duckt zurück. Umpositionieren kostet einen Moment, Heraustreten ist eine Verpflichtung — jede Entscheidung ist eine Ausgabe, kein Zucken. Farbe verhält sich wie Farbe: Streukegel, Luftwiderstand, Fallhöhe, Abpraller an den Bunkern und Trades — ein Ball, der bereits in der Luft ist, kann den Spieler noch treffen, der einen gerade eliminiert hat.

Ein Duell von der On-Deck-Karte über das Live-Spiel bis zum Verdict-Wipe

Was ich gebaut habe

  • Eine headless, deterministische Simulation mit festem 1/120-s-Schritt, geseedetem und aufgeteiltem Zufallsstrom, World-Hash und Replay aus Input-Logs — die Sim berührt nie das DOM, dieselbe Partie lässt sich also überall erneut ausführen und verifizieren
  • Eine WebGL-Render-Pipeline (three.js) über dieser Sim mit canvas2d-Fallback: Charaktere aus einem geriggten Low-Poly-Mesh gebacken, echte Bunker-Meshes aus dem NXL/PSP-Kit, Farbspritzer, Verdict-Wipes und eine strikte Einweg-Abhängigkeitsgrenze core → sim → render
  • Einen KI-Rivalen, der alle 0,3–1,2 s entscheidet, ob er späht, unterdrückt, sich einzieht oder wartet, mit menschlicher Zielverzögerung — fünf benannte Rivalen mit eigenen Gewohnheiten
  • Hold-and-Steer-Touch-Steuerung: Positions-Pad, Ziel-Pad und FIRE-Taste, magnetisiert, sodass der Daumen in seiner Zone bleibt, bis er sich klar für eine andere entscheidet
  • Karrierestatistiken, Run-Records und ein per Replay verifizierbares Leaderboard-Rückgrat, gespeichert über eine Plattformschicht, damit Spielstände auf Web, iOS, Android und Desktop überleben
  • Lockstep-Netcode: ein WebSocket-Relay auf einem Cloudflare Worker mit Durable Objects, Wire-Protokoll, Latenzleiter und gespiegelte Gast-Ansicht, sodass zwei echte Engines eine Partie über das Relay mit identischen Welten spielen
  • Rund 1.760 Tests in 97 Dateien, darunter Freeze-Guards, die die CI brechen lassen, wenn sich eine eingefrorene visuelle Fläche ändert, und Vokabular-Tests, die jeden spielerseitigen String festnageln

Ein Designsystem mit zwei Stimmen

Die visuelle Identität „Match Data“ ist druckinspiriert und helligkeitsgetrieben: eine warme Neutralleiter aus Kitt und Tinte, ein einziger bernsteinfarbener SIGNAL-Akzent und eine pro Partie gewürfelte Neonfarbe als einzige laute Farbe auf dem Bildschirm. Sie spricht in zwei Registern. STATEMENT ist im Match: Anton-Schlagzeilen, gekippte Verdict-Wipes, Schiedsrichterrufe wie GAME ON!, HIT! und TRADE!. PAPER ist überall sonst: ruhiges Druck-Mobiliar, gesperrte Versalien, harte versetzte Schatten, null Ausrufezeichen. Identität entsteht durch Struktur — Tintenrahmen, Radius null, Schatten nach rechts unten — nicht durch Farbe.

Das System liegt als versioniertes Bundle im Repo: Tokens, Komponentenspezifikationen, Motion-Tabellen und ein ratifiziertes Vokabular, das drei Generationen widersprüchlicher Texte in eine Tabelle aufgelöst hat — jede Zeile durch einen Test abgesichert.

Trade-Verdict, das Gear-Bag-Loadout und die Karriere-Statistikkarte

Determinismus beweisen, bevor man darauf baut

Multiplayer, Replays und Leaderboard beruhen auf einer Behauptung: Zwei Simulationen mit denselben Eingaben erzeugen bitgenau dieselbe Welt. Statt das zu argumentieren, habe ich es gemessen — 200 Seeds × 3.000 Ticks über zwei unabhängige Welten, verbunden nur durch eine modellierte Leitung, bei sauberer Verbindung, 60 ms und 200 ms Round-Trip und bei Bildraten von 60 bis 240 fps, ohne eine einzige Abweichung. Dann spielten zwei echte Engines ein komplettes Race to 5 über das Live-Relay, mit durchgehend identischen Welten und Phasen. Ein adversariales Audit der gespiegelten Gast-Ansicht brachte 26 Befunde, 18 davon bestätigt — darunter drei Fehler, die kein Hash-Vergleich je hätte finden können, weil beide Clients identisch falsch lagen.

Bunker, die wie Bunker blocken

Das Feld nimmt die echten aufblasbaren Formen, hinter denen Spieler snap-shooten — Doritos, Cans, Cakes, Temples, das X, der Rollie. Die jüngste Regelrevision hat die rechteckige Hitbox jedes Bunkers durch seine tatsächliche Kontur ersetzt. Farbe, die knapp an der Ecke eines Bunkers vorbeiging, starb früher an leerer Luft; jetzt fliegt sie durch, und Abpraller kommen von der echten Rundung. Jede Regeländerung erhöht eine versionierte Konfiguration, die die Messungen dahinter mitführt, und macht alte Replays absichtlich ungültig — die Kollisionsgeometrie ist Teil der Regeln.

Status

In privater Beta. Practice gegen den KI-Rivalen läuft offline, private Matches laufen über das Relay, Matchmaking ist noch nicht gebaut. Die iOS-Shell baut über Capacitor, die Desktop-Shells über Tauri 2. Als Nächstes: der Performance-Pass auf dem Gerät, die Serverseite des Leaderboards und die Store-Einreichung.

Das Spiel ist in aktiver Entwicklung. Wer die Beta auf iOS, Android oder Desktop testen möchte: Schreib mir, und ich schicke einen Build.