Würfel, die wirklich taumeln: der neue 3D-Wurf
Die Brettwürfel sind jetzt echte 3D-Würfel, die ausholen, taumeln und auf deinen Zahlen landen – ohne künstliche Verzögerung und schonend bei reduzierter Bewegung.

Kurz gesagt
Würfeln war früher flach: Die Zahlen klappten einfach um. Jetzt sind die beiden Bewegungswürfel – und der Speed-Würfel – echte 3D-Würfel, die sich ducken, abspringen und durch die Luft taumeln, bevor sie mit der Augenzahl nach oben auf dem Tisch zur Ruhe kommen.
Das Schöne daran: Die Würfel drehen sich nur, solange das Spiel deinen Zug ausrechnet, dann fallen sie und landen auf genau den Zahlen, die du geworfen hast. Es gibt keine aufgepolsterte, künstliche Pause – in dem Moment, in dem dein Ergebnis feststeht, fallen sie. Bei einer schnellen Verbindung ist die ganze Sache im Nu vorbei.
- Ein kurzes Ausholen in dem Augenblick, in dem du auf Würfeln tippst, damit es sich sofort reaktionsschnell anfühlt.
- Ein echtes Taumeln durch die Luft, während dein Zug berechnet wird – es dehnt sich natürlich, wenn der Server langsam ist, statt einen Platzhalter zu zeigen.
- Eine weiche Landung auf deinen tatsächlichen Zahlen, wobei deine Figur in dem Moment losläuft, in dem die Würfel liegen.
- Der Speed-Würfel macht mit und zeigt zwischen den Würfen weiterhin ein dezentes „?“, damit du immer weißt, dass er im Spiel ist.

Es ist eine rein optische Änderung – die Regeln, die Wahrscheinlichkeiten und das Brett spielen sich genau wie vorher. Die Würfel fühlen sich nur endlich wie Würfel an.
Für technisch Neugierige
Jeder Würfel ist ein sechsseitiger 3D-CSS-Würfel, angetrieben von einem kleinen Zustandsautomaten, der idle → windup → loop → settle → jitter → landed durchläuft. Die Ausrichtung wird als Quaternion gespeichert, sodass wir um jede beliebige Achse drehen und pro Bild in ein einzelnes CSS rotate3d() umrechnen können; FACE_Q ordnet jedem Wert 1–6 die Ausrichtung zu, die diese Augenseite nach vorn bringt.
// apps/web/app/[locale]/game/[id]/dice3d.ts
// quaternion per face → one CSS rotate3d() at rest
const FACE_Q: Record<DieValue, Quat> = {
1: Q.identity,
2: Q.axis([0, 1, 0], +Math.PI / 2),
3: Q.axis([0, 1, 0], -Math.PI / 2),
4: Q.axis([1, 0, 0], +Math.PI / 2),
5: Q.axis([1, 0, 0], -Math.PI / 2),
6: Q.axis([1, 0, 0], Math.PI),
};Der Wurf ist optimistisch: Ein Tippen erhöht eine optimistische Nonce und startet damit das 180 ms lange Ausholen und eine unbestimmt lange Taumelschleife. Wenn der maßgebliche Wurf eintrifft (eine Erhöhung von rollSeq), kommt der sich drehende Würfel sofort über die kürzeste Vorwärtsdrehung auf FACE_Q[value] zur Ruhe und fällt – es gibt keine Mindestdrehzeit, eine schnelle Antwort landet also einen schnellen Wurf.
// authoritative values arrive → settle now, no spin floor
onRollSeq(values) {
values.forEach((v, i) => {
if (controller[i].isSpinning) controller[i].setResult(v, arrival + i * 78);
else controller[i].startRoll(arrival), controller[i].setResult(v, /* after windup */);
});
}Auf Entscheidung des Eigentümers wurden die abklingenden Aufprallsprünge aus der Design-Vorlage gestrichen (Restitution 0), sodass das Setzen ein einziger weicher, beschleunigender Fall ist, der genau auf dem Wert aufsetzt und nur ein kurzes gedämpftes Wackeln übrig lässt. Eine gemeinsame rAF-Schleife läuft nur, solange ein Würfel animiert wird, jede Phase nutzt absolute Zeitstempel aus performance.now() (sodass ein in den Hintergrund geschobener Tab korrekt vorspult), und eine Rückfallsicherung setzt auf die aktuellen Store-Werte, falls kein Wurf eintrifft. Bei reduzierter Bewegung entfällt die optimistische Nonce ganz und es werden nur die Seiten getauscht. Nur Web: Engine, Daemon und Datenbank bleiben unangetastet.