Guides · Länder · Blog

Wie wir das Boxspiel gebaut haben

Ein Kampfspiel ist ein Haufen 70-Millisekunden-Fenster. So wurde ein Paket daraus: pure Regeln, eine Frame-Data-Tabelle, ein Verteidiger, der immer recht hat, und das eine, was kein Client entscheiden darf.

Gegen die Quellen geprüft am 2026-08-30

Was es ist - und was absichtlich nicht

Das Boxspiel ist ein Paket, @kxb/boxing, das die Engine der Plattform (@kxb/xp) als SDK integriert. Es ist kein XP: kein Dokument, kein Level, nichts, was der Editor öffnen könnte. Es importiert fünf Schnittstellen - Identität, Transport, Uhr, Autorität - und bekommt dafür Multiplayer gegen unser Supabase, gegen zwei Tabs auf einem Laptop oder gegen ein Backend, das hier niemand je gesehen hat.

Diese Unterscheidung war die erste Entscheidung. Die Engine hat ein allgemeines Dokumentformat, und ein Kampfspiel besteht aus sehr speziellen Regeln über sehr kurze Fenster. Beides als Level auszudrücken hätte beide verbogen; fünf Interfaces zu importieren verbiegt nichts.

Die zweite frühe Entscheidung: Das Spiel bringt seine eigenen Pixel mit. Boxing liefert Grafik und React-Szene im Paket - was aus „den Ordner in ein eigenes Repository heben" einen wahren Satz macht statt eines Vorsatzes.

Der Bau, in der Reihenfolge, in der er passiert ist

  1. Regeln zuerst, und pur

    Alles außer der Netzwerkschicht ist Zahlen rein, Zahlen raus - kein Browser, kein Canvas, keine eigene Uhr. Diese Reinheit ist keine Ästhetik: Die Umgebung, in der das gebaut wurde, feuert nie requestAnimationFrame, ein laufender Kampf ließ sich also nicht anschauen. `bun test packages/boxing` spielt ganze Drei-Runden-Kämpfe in Millisekunden, und nur deshalb kann man den Regeln trauen.

    Achtung: Wenn deine Regeln einen Browser brauchen, kannst du einen Kampf nicht schneller testen, als du ihn spielst - und dann tust du es nicht.

  2. Das ganze Spielgefühl in einer Tabelle

    Ein Jab ist nicht „ein schneller Schlag". Er ist 70 ms, bevor er jemandem wehtun kann, 50 ms, in denen er es kann, und 130 ms Bindung danach, in denen du dich nicht verteidigen kannst. Diese Zahlen sind das komplette Gefühl des Spiels, also wohnen sie in einem Datensatz pro Move - die Frame Data - und die Simulation liest die Tabelle. Das Spiel zu balancieren heißt, eine Datei zu editieren.

    Die Zahlen stehen in Sekunden, nicht in Frames, dem Genre-Vokabular zum Trotz: Der Host liefert die Uhr, ein Test treibt einen Kampf in einer Schleife, ohne auf eine zu warten - und ein Move in Frames ändert auf einem 144-Hz-Monitor seine Länge. Nur die Sprite-Sheets denken noch in Frames, und genau eine Funktion kennt beides.

  3. Autorität dorthin, wo Lag am meisten wehtäte

    Schaden entscheidet der Verteidiger, auf seinem eigenen Client. Ein Schlag, der mich trifft, ist eine Tatsache über meine Gesundheit, und jede andere Anordnung verliert gegen Lag auf eine Art, die Spieler nie verzeihen. Die Rundenuhr gehört dem Client der roten Ecke. Beides geht in Ordnung, weil Irrtümer darüber sichtbar und selbstkorrigierend sind: Ein Kämpfer, der ein paar Zentimeter daneben steht, wird vom nächsten Paket geradegerückt, eine Glocke 100 ms zu früh ist eine Glocke.

  4. Außer dem Ergebnis

    Ein Ergebnis ist anders als alles andere im Spiel: Es wird aufgeschrieben, von jemandem gelesen, der nicht dabei war, und nichts korrigiert es später. Also geht das Ergebnis an den Arbiter - die eine Ebene, die kein Client entscheiden darf - und der Report ist idempotent: Beide Clients sehen denselben Kampf enden, beide dürfen ihn melden, der erste Report gewinnt und der zweite bekommt das gespeicherte Ergebnis statt eines Fehlers. Ein Client, der zweimal gefragt hat, weil seine erste Frage verloren ging, hat nichts falsch gemacht.

    Achtung: Ein Punktestand, der überschrieben werden kann, ist ein Punktestand, den jemand überschreiben kann. Sortiere die Fakten deines Spiels nach diesem Satz.

  5. Der Draht, zuletzt

    Fünf Nachrichtentypen auf drei Takten, und jeder Client sagt nur die eigenen Schläge voraus - weil er muss, nicht weil Prediction Spaß macht. Der Transport ist eines der fünf importierten Interfaces - deshalb läuft derselbe Kampf über Supabase Realtime, über zwei Tabs oder über eine Map im Test.

Die Wörter im Code

@kxb/xp/host
Die fünf Ports, die ein Spiel importiert: Identität, Transport, Uhr, Autorität, Persistenz.
Frame Data
Die eine Tabelle, was jeder Move kostet und wie lange er dauert - das ganze Gefühl des Spiels.
Arbiter
Die Autoritätsebene für Fakten, die kein Client entscheiden darf. Hier: nur das Ergebnis.
memoryHost
Der In-Memory-Host, mit dem ein Test zwei Spieler ist, ohne Netzwerk.
Wire
Was wirklich über den Socket geht, und wie man es liest.

Was wir uns am Anfang sagen würden

  • Tune in einer Datei, oder du wirst nie tunen. Acht switch-Arme mit derselben Zahl sind ein Spiel, das niemand balancieren kann.
  • Autorität ist kein Prinzip, sondern eine Entscheidung pro Fakt: selbstkorrigierende Fakten an den Client, dem Lag wehtut; dauerhafte Fakten an den Arbiter.
  • Mach jeden Autoritäts-Call idempotent, bevor du es brauchst.
  • Sekunden, nicht Frames - überall, wo ein Host die Uhr liefert.
  • Wenn die Dev-Umgebung das Spiel nicht rendern kann, lass die Regeln ohne sie laufen - die Einschränkung entpuppte sich als die Architektur.

Lies das Original

Das hier ist eine Landkarte, keine Rechts- oder Steuerberatung - und eine ehrliche darüber, wie sie entstanden ist: Der Deutschland-Guide stammt von jemandem, der den Weg gegangen ist; die meisten anderen Länder wurden mit KI aus den offiziellen Quellen erstellt und noch von niemandem abgelaufen, der es getan hat. Gesetze ändern sich. Jeder Guide trägt das Datum seiner letzten Prüfung und die Quellen zum Selbst-Nachlesen - und wer einen dieser Wege hinter sich hat: Genau diese Korrekturen wünscht sich das Handbuch.