summaryrefslogtreecommitdiffstats
path: root/web/play/src/slots.ts
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-11-08 03:32:24 +0100
committersalmonik <salmonik@tuta.io>2026-11-08 03:32:24 +0100
commitfda24c47a8262388ada92722850a362da65aaa6e (patch)
tree13363fa1461ae4e10087acba562a527b8bde4228 /web/play/src/slots.ts
parentv5.0.0: protocol v5 and the browser frontend (diff)
downloadzagan-bet-fda24c47a8262388ada92722850a362da65aaa6e.tar.gz
zagan-bet-fda24c47a8262388ada92722850a362da65aaa6e.zip
web: accept the serialized reels array and stop game loops on navigation
The Rust SlotsView serializes reels as an array of chars, so the browser joins it instead of String(array). The crash chart, reel animation and roulette observer now stop when another screen takes over, and a returning crash screen rebuilds its detached canvas. Action buttons ignore a double click before the server view arrives. Also tightens the gateway session registry with a generation token, caps WebSocket messages at 64 KiB, uses the __Host- cookie prefix on HTTPS, and ships the systemd unit.
Diffstat (limited to '')
-rw-r--r--web/play/src/slots.ts18
1 files changed, 17 insertions, 1 deletions
diff --git a/web/play/src/slots.ts b/web/play/src/slots.ts
index dba1e25..7c4677d 100644
--- a/web/play/src/slots.ts
+++ b/web/play/src/slots.ts
@@ -7,6 +7,7 @@ const SYMBOLS = "CLOGDS";
7const LINE_NAMES = ["top", "middle", "bottom", "V", "inverted V"]; 7const LINE_NAMES = ["top", "middle", "bottom", "V", "inverted V"];
8 8
9let spinUntil = 0; 9let spinUntil = 0;
10let lastSpin = 0;
10let animation: number | undefined; 11let animation: number | undefined;
11let latest: View | null = null; 12let latest: View | null = null;
12let latestBoard: HTMLElement | null = null; 13let latestBoard: HTMLElement | null = null;
@@ -15,6 +16,17 @@ export function requestSlotsSpin(): void {
15 spinUntil = Date.now() + 900; 16 spinUntil = Date.now() + 900;
16} 17}
17 18
19/// Stop the reel animation when another screen takes over.
20export function stopSlotsAnimation(): void {
21 if (animation !== undefined) {
22 window.clearInterval(animation);
23 animation = undefined;
24 }
25 latest = null;
26 latestBoard = null;
27 spinUntil = 0;
28}
29
18function spinning(view: View): boolean { 30function spinning(view: View): boolean {
19 return view.phase === "spinning" || Date.now() < spinUntil; 31 return view.phase === "spinning" || Date.now() < spinUntil;
20} 32}
@@ -42,7 +54,9 @@ export function renderSlots(
42 54
43 const reels = node("div", "reels"); 55 const reels = node("div", "reels");
44 const tiles: HTMLElement[] = []; 56 const tiles: HTMLElement[] = [];
45 const flat = String(view.reels ?? ""); 57 const flat = Array.isArray(view.reels)
58 ? view.reels.join("")
59 : String(view.reels ?? "");
46 for (let column = 0; column < REELS; column += 1) { 60 for (let column = 0; column < REELS; column += 1) {
47 const reel = node("div", "reel"); 61 const reel = node("div", "reel");
48 for (let row = 0; row < ROWS; row += 1) { 62 for (let row = 0; row < ROWS; row += 1) {
@@ -133,6 +147,8 @@ export function renderSlots(
133 const spin = node("button", "btn primary wide big", active ? "SPINNING…" : "SPIN"); 147 const spin = node("button", "btn primary wide big", active ? "SPINNING…" : "SPIN");
134 spin.disabled = active; 148 spin.disabled = active;
135 spin.addEventListener("click", () => { 149 spin.addEventListener("click", () => {
150 if (Date.now() - lastSpin < 900) return;
151 lastSpin = Date.now();
136 requestSlotsSpin(); 152 requestSlotsSpin();
137 send("Spin"); 153 send("Spin");
138 }); 154 });