lobby: 20 hand-composed game posters (symbol-svg mirrors reel art); crash engine + 10 risk game definitions certified; crash_rounds table
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
24 changed files +6,600 −55
modified
apps/simulator/src/cli.ts
+14 −3
@@ -10,8 +10,8 @@ | ||
| 10 | 10 | import fs from "node:fs"; |
| 11 | 11 | import path from "node:path"; |
| 12 | 12 | import { fileURLToPath } from "node:url"; |
| 13 | −import { certify, formatCertification, validateDefinition, DEFAULT_CERTIFICATION_RULES } from "@spinza/game-core"; | |
| 14 | −import { RAW_GAMES, GAMES } from "@spinza/games"; | |
| 13 | +import { certify, certifyCrash, formatCertification, simulateCrash, validateDefinition, DEFAULT_CERTIFICATION_RULES } from "@spinza/game-core"; | |
| 14 | +import { RAW_GAMES, GAMES, CRASH_GAMES, CRASH_BY_SLUG } from "@spinza/games"; | |
| 15 | 15 | import { calibrate, simulateParallel } from "./index"; |
| 16 | 16 | |
| 17 | 17 | const here = path.dirname(fileURLToPath(import.meta.url)); |
@@ -94,7 +94,18 @@ async function main() { | ||
| 94 | 94 | fs.mkdirSync(certDir, { recursive: true }); |
| 95 | 95 | const spins = num("spins", 1_000_000); |
| 96 | 96 | let failed = 0; |
| 97 | − for (const slug of targets(sel)) { | |
| 97 | + const list = sel === "crash" ? CRASH_GAMES.map((g) => g.slug) : targets(sel); | |
| 98 | + for (const slug of list) { | |
| 99 | + const crashDef = CRASH_BY_SLUG.get(slug); | |
| 100 | + if (crashDef) { | |
| 101 | + console.log(`\nCertifying ${crashDef.name} (${slug}@${crashDef.version}, crash) — ${spins.toLocaleString("en-US")} rounds`); | |
| 102 | + const res = simulateCrash(crashDef, { spins }); | |
| 103 | + const report = certifyCrash(crashDef, res, { ...DEFAULT_CERTIFICATION_RULES, minSpins: Math.min(DEFAULT_CERTIFICATION_RULES.minSpins, spins) }); | |
| 104 | + fs.writeFileSync(path.join(certDir, `${slug}.json`), JSON.stringify(report, null, 2) + "\n"); | |
| 105 | + console.log(formatCertification(report)); | |
| 106 | + if (report.status === "FAIL") failed++; | |
| 107 | + continue; | |
| 108 | + } | |
| 98 | 109 | const g = GAMES.find((x) => x.slug === slug)!; |
| 99 | 110 | console.log(`\nCertifying ${g.name} (${slug}@${g.version}) payScale=${g.payScale} — ${spins.toLocaleString("en-US")} spins`); |
| 100 | 111 | const res = await simulateParallel(slug, { spins, payScale: g.payScale, threads, onProgress: progressBar }); |
modified
apps/web/src/components/lobby/game-art.tsx
+50 −50
@@ -94,7 +94,7 @@ const DIMS: Record<ArtVariant, { w: number; h: number }> = { | ||
| 94 | 94 | function focal(v: ArtVariant, W: number, H: number, showName: boolean): { cx: number; cy: number; R: number } { |
| 95 | 95 | switch (v) { |
| 96 | 96 | case "card": |
| 97 | − return { cx: W / 2, cy: showName ? H * 0.41 : H * 0.5, R: W * 0.42 }; | |
| 97 | + return { cx: W / 2, cy: showName ? H * 0.385 : H * 0.5, R: W * 0.405 }; | |
| 98 | 98 | case "tile": |
| 99 | 99 | return { cx: W / 2, cy: H / 2, R: W * 0.4 }; |
| 100 | 100 | case "hero": |
@@ -212,7 +212,7 @@ function NeonVault(s: Stage) { | ||
| 212 | 212 | <Sym s={s} id="V" x={cx - R * 0.78} y={cy - R * 0.5} size={R * 0.4} rotate={-8} /> |
| 213 | 213 | <rect x={f(cx - R * 1.1)} y={f(scanY - R * 0.05)} width={f(R * 2.2)} height={f(R * 0.1)} fill={`url(#${id}-nv3)`} /> |
| 214 | 214 | <line x1={f(cx - R * 1.1)} y1={f(scanY)} x2={f(cx + R * 1.1)} y2={f(scanY)} stroke={p.secondary} strokeWidth={1.5} strokeOpacity={0.9} /> |
| 215 | − <Small x={cx} y={cy + R * 1.18} text="×2 ×3 ×5 ×8 ×12 ×20 ×30 ×50" color={p.primary} size={R * 0.075} tracking="0.18em" opacity={0.7} /> | |
| 215 | + <Small x={cx} y={cy + R * 1.0} text="×2 ×3 ×5 ×8 ×12 ×20 ×30 ×50" color={p.primary} size={R * 0.075} tracking="0.18em" opacity={0.7} /> | |
| 216 | 216 | </> |
| 217 | 217 | ) : null} |
| 218 | 218 | </g> |
@@ -257,7 +257,7 @@ function CosmicCollapse(s: Stage) { | ||
| 257 | 257 | ? orbit.map((o) => <Sym key={o.id} s={s} id={o.id} x={cx + Math.cos(o.a) * R * o.d} y={cy + Math.sin(o.a) * R * o.d * 0.72} size={R * o.k} rotate={o.rot} />) |
| 258 | 258 | : null} |
| 259 | 259 | {!compact ? ( |
| 260 | − <text x={f(cx)} y={f(cy + R * 1.22)} textAnchor="middle" dominantBaseline="central" fontWeight={700} fill={p.primary} style={{ fontFamily: FONT, letterSpacing: "0.1em" }}> | |
| 260 | + <text x={f(cx)} y={f(cy + R * 1.0)} textAnchor="middle" dominantBaseline="central" fontWeight={700} fill={p.primary} style={{ fontFamily: FONT, letterSpacing: "0.1em" }}> | |
| 261 | 261 | <tspan fontSize={f(R * 0.07)} fillOpacity={0.35}>×1 ×2 ×3 ×5 ×8 </tspan> |
| 262 | 262 | <tspan fontSize={f(R * 0.11)} fill={p.glow} fillOpacity={0.9}>×13</tspan> |
| 263 | 263 | </text> |
@@ -279,7 +279,7 @@ function GoldenEmperor(s: Stage) { | ||
| 279 | 279 | { x: cx, m: "×3" }, |
| 280 | 280 | { x: cx + R * 0.66, m: "×5" }, |
| 281 | 281 | ]; |
| 282 | − const py = cy + R * 0.62; | |
| 282 | + const py = cy + R * 0.55; | |
| 283 | 283 | return ( |
| 284 | 284 | <g> |
| 285 | 285 | <defs> |
@@ -301,7 +301,7 @@ function GoldenEmperor(s: Stage) { | ||
| 301 | 301 | {pearls.map((o) => ( |
| 302 | 302 | <g key={o.m}> |
| 303 | 303 | <Sym s={s} id="W" x={o.x} y={py} size={R * 0.5} /> |
| 304 | − <Pill x={o.x} y={py + R * 0.38} text={o.m} color={p.primary} ink={p.glow} size={R * 0.085} /> | |
| 304 | + <Pill x={o.x} y={py + R * 0.36} text={o.m} color={p.primary} ink={p.glow} size={R * 0.085} /> | |
| 305 | 305 | </g> |
| 306 | 306 | ))} |
| 307 | 307 | <Sym s={s} id="S" x={cx - R * 0.7} y={cy - R * 0.4} size={R * 0.4} /> |
@@ -332,9 +332,9 @@ function DiamondHeist(s: Stage) { | ||
| 332 | 332 | const lasers = `M${f(cx - R * 1.4)} ${f(cy - R * 1.3)}L${f(cx + R * 1.4)} ${f(cy + R * 0.2)} M${f(cx - R * 1.4)} ${f(cy + R * 0.9)}L${f(cx + R * 1.4)} ${f(cy - R * 1.1)}`; |
| 333 | 333 | const tiers = ["MINI", "MINOR", "MAJOR", "GRAND"]; |
| 334 | 334 | const coins = [ |
| 335 | − { x: cx - R * 0.72, y: cy + R * 0.62, v: "5×" }, | |
| 336 | − { x: cx, y: cy + R * 0.8, v: "20×" }, | |
| 337 | − { x: cx + R * 0.72, y: cy + R * 0.62, v: "10×" }, | |
| 335 | + { x: cx - R * 0.72, y: cy + R * 0.5, v: "5×" }, | |
| 336 | + { x: cx, y: cy + R * 0.66, v: "20×" }, | |
| 337 | + { x: cx + R * 0.72, y: cy + R * 0.5, v: "10×" }, | |
| 338 | 338 | ]; |
| 339 | 339 | return ( |
| 340 | 340 | <g> |
@@ -360,16 +360,16 @@ function DiamondHeist(s: Stage) { | ||
| 360 | 360 | {coins.map((c) => ( |
| 361 | 361 | <g key={c.v}> |
| 362 | 362 | <Sym s={s} id="D" x={c.x} y={c.y} size={R * 0.4} /> |
| 363 | − <Pill x={c.x} y={c.y + R * 0.3} text={c.v} color={p.primary} ink={p.glow} size={R * 0.08} /> | |
| 363 | + <Pill x={c.x} y={c.y + R * 0.28} text={c.v} color={p.primary} ink={p.glow} size={R * 0.08} /> | |
| 364 | 364 | </g> |
| 365 | 365 | ))} |
| 366 | 366 | {tiers.map((t, i) => { |
| 367 | − const y = cy - R * 1.15 + i * R * 0.27; | |
| 367 | + const y = cy - R * 0.62 + i * R * 0.3; | |
| 368 | 368 | const grand = i === 3; |
| 369 | 369 | return <Pill key={t} x={cx + R * 1.02} y={y} text={t} color={grand ? "#ffd166" : p.secondary} ink={grand ? "#ffd166" : "#dfe4ea"} bg={grand ? "#2a2008" : "#000"} size={R * 0.075} w={R * 0.5} />; |
| 370 | 370 | })} |
| 371 | − <Sym s={s} id="W" x={cx - R * 0.98} y={cy - R * 0.55} size={R * 0.5} rotate={-30} /> | |
| 372 | − <Sym s={s} id="P1" x={cx - R * 1.0} y={cy - R * 1.08} size={R * 0.38} /> | |
| 371 | + <Sym s={s} id="W" x={cx - R * 1.0} y={cy - R * 0.62} size={R * 0.5} rotate={-30} /> | |
| 372 | + <Sym s={s} id="P1" x={cx + R * 1.0} y={cy - R * 1.0} size={R * 0.38} /> | |
| 373 | 373 | </> |
| 374 | 374 | ) : null} |
| 375 | 375 | <path d={sparkles} fill="#fff" fillOpacity={0.85} /> |
@@ -416,7 +416,7 @@ function ArcticFortune(s: Stage) { | ||
| 416 | 416 | <Sym s={s} id="P1" x={cx + R * 0.72} y={cy + R * 0.5} size={R * 0.62} /> |
| 417 | 417 | <Sym s={s} id="H1" x={cx - R * 0.78} y={cy - R * 0.45} size={R * 0.44} /> |
| 418 | 418 | <Sym s={s} id="S" x={cx + R * 0.1} y={cy - R * 0.7} size={R * 0.38} /> |
| 419 | − <Small x={cx} y={cy + R * 1.22} text="×1 ×2 ×3 ×4 ×5" color="#e8f8ff" size={R * 0.08} tracking="0.16em" opacity={0.75} /> | |
| 419 | + <Small x={cx} y={cy + R * 1.0} text="×1 ×2 ×3 ×4 ×5" color="#e8f8ff" size={R * 0.08} tracking="0.16em" opacity={0.75} /> | |
| 420 | 420 | </> |
| 421 | 421 | ) : ( |
| 422 | 422 | <Sym s={s} id="W" x={cx} y={cy} size={R * 0.9} /> |
@@ -472,7 +472,7 @@ function InfernoReels(s: Stage) { | ||
| 472 | 472 | <Sym s={s} id="S" x={cx + R * 0.92} y={cy - R * 0.75} size={R * 0.46} rotate={16} /> |
| 473 | 473 | <Sym s={s} id="H1" x={cx - R * 0.95} y={cy + R * 0.55} size={R * 0.42} rotate={22} /> |
| 474 | 474 | <Sym s={s} id="H2" x={cx + R * 0.95} y={cy + R * 0.55} size={R * 0.42} rotate={-20} /> |
| 475 | − <Small x={cx} y={cy + R * 1.2} text="×2 · ×3 · ×5 · ×10" color="#ffd166" size={R * 0.085} tracking="0.16em" weight={700} opacity={0.9} /> | |
| 475 | + <Small x={cx} y={cy + R * 1.0} text="×2 · ×3 · ×5 · ×10" color="#ffd166" size={R * 0.085} tracking="0.16em" weight={700} opacity={0.9} /> | |
| 476 | 476 | </> |
| 477 | 477 | ) : null} |
| 478 | 478 | <path d={embers} fill={p.glow} fillOpacity={0.8} /> |
@@ -531,7 +531,7 @@ function QuantumJackpot(s: Stage) { | ||
| 531 | 531 | <Sym s={s} id="W" x={cx - R * 0.85} y={cy - R * 0.85} size={R * 0.48} /> |
| 532 | 532 | <Sym s={s} id="H1" x={cx + R * 0.85} y={cy - R * 0.9} size={R * 0.44} /> |
| 533 | 533 | <Sym s={s} id="S" x={cx - R * 0.9} y={cy + R * 0.7} size={R * 0.4} /> |
| 534 | − <Small x={cx} y={cy + R * 1.25} text="MINI 20× · MINOR 50× · MAJOR 200× · GRAND 1,000×" color={p.glow} size={R * 0.062} tracking="0.1em" opacity={0.8} /> | |
| 534 | + <Small x={cx} y={cy + R * 1.0} text="MINI 20× · MINOR 50× · MAJOR 200× · GRAND 1,000×" color={p.glow} size={R * 0.062} tracking="0.1em" opacity={0.8} /> | |
| 535 | 535 | </> |
| 536 | 536 | ) : null} |
| 537 | 537 | </g> |
@@ -603,8 +603,8 @@ function MidnightTokyo(s: Stage) { | ||
| 603 | 603 | /* 09 — PHARAOH PROTOCOL: pyramid with a scanning laser, artifact meter */ |
| 604 | 604 | function PharaohProtocol(s: Stage) { |
| 605 | 605 | const { W, H, cx, cy, R, id, p, compact } = s; |
| 606 | − const base = cy + R * 0.85; | |
| 607 | − const apex = cy - R * 0.85; | |
| 606 | + const base = cy + R * 0.7; | |
| 607 | + const apex = cy - R * 0.98; | |
| 608 | 608 | const half = R * 1.05; |
| 609 | 609 | const tri = `${f(cx - half)},${f(base)} ${f(cx)},${f(apex)} ${f(cx + half)},${f(base)}`; |
| 610 | 610 | let bricks = ""; |
@@ -614,7 +614,7 @@ function PharaohProtocol(s: Stage) { | ||
| 614 | 614 | const segs = 12; |
| 615 | 615 | const mw = R * 1.4; |
| 616 | 616 | const mx = cx - mw / 2; |
| 617 | − const my = cy + R * 1.12; | |
| 617 | + const my = cy + R * 0.86; | |
| 618 | 618 | let segOff = ""; |
| 619 | 619 | let segOn = ""; |
| 620 | 620 | for (let i = 0; i < segs; i++) { |
@@ -633,8 +633,8 @@ function PharaohProtocol(s: Stage) { | ||
| 633 | 633 | </clipPath> |
| 634 | 634 | </defs> |
| 635 | 635 | <rect width={W} height={H} fill={`url(#${id}-pp1)`} /> |
| 636 | − <circle cx={f(cx + R * 0.75)} cy={f(cy - R * 0.72)} r={f(R * 0.55)} fill={`url(#${id}-pp3)`} /> | |
| 637 | − <circle cx={f(cx + R * 0.75)} cy={f(cy - R * 0.72)} r={f(R * 0.2)} fill="#fb923c" fillOpacity={0.9} /> | |
| 636 | + <circle cx={f(cx + R * 0.78)} cy={f(cy - R * 0.8)} r={f(R * 0.55)} fill={`url(#${id}-pp3)`} /> | |
| 637 | + <circle cx={f(cx + R * 0.78)} cy={f(cy - R * 0.8)} r={f(R * 0.2)} fill="#fb923c" fillOpacity={0.9} /> | |
| 638 | 638 | <ellipse cx={f(cx - R * 0.6)} cy={f(base + R * 0.15)} rx={f(W * 0.7)} ry={f(R * 0.3)} fill="#3a2810" /> |
| 639 | 639 | <ellipse cx={f(cx + R * 0.9)} cy={f(base + R * 0.25)} rx={f(W * 0.6)} ry={f(R * 0.28)} fill="#2a1c0a" /> |
| 640 | 640 | <polygon points={tri} fill={`url(#${id}-pp2)`} /> |
@@ -645,14 +645,14 @@ function PharaohProtocol(s: Stage) { | ||
| 645 | 645 | <Sym s={s} id="W" x={cx} y={apex - R * 0.05} size={R * 0.72} plate={false} /> |
| 646 | 646 | {!compact ? ( |
| 647 | 647 | <> |
| 648 | − <Sym s={s} id="P1" x={cx + R * 0.62} y={cy + R * 0.35} size={R * 0.62} /> | |
| 649 | − <Sym s={s} id="H1" x={cx - R * 0.8} y={cy + R * 0.3} size={R * 0.5} /> | |
| 650 | − <Sym s={s} id="AR" x={cx - R * 0.55} y={cy + R * 0.72} size={R * 0.36} /> | |
| 651 | − <Sym s={s} id="AR" x={cx - R * 0.2} y={cy + R * 0.78} size={R * 0.36} /> | |
| 652 | − <Sym s={s} id="AR" x={cx + R * 0.15} y={cy + R * 0.72} size={R * 0.36} /> | |
| 648 | + <Sym s={s} id="P1" x={cx + R * 0.66} y={cy + R * 0.22} size={R * 0.62} /> | |
| 649 | + <Sym s={s} id="H1" x={cx - R * 0.82} y={cy + R * 0.18} size={R * 0.5} /> | |
| 650 | + <Sym s={s} id="AR" x={cx - R * 0.5} y={cy + R * 0.6} size={R * 0.36} /> | |
| 651 | + <Sym s={s} id="AR" x={cx - R * 0.15} y={cy + R * 0.64} size={R * 0.36} /> | |
| 652 | + <Sym s={s} id="AR" x={cx + R * 0.2} y={cy + R * 0.6} size={R * 0.36} /> | |
| 653 | 653 | <path d={segOff} fill="#fff" fillOpacity={0.12} /> |
| 654 | 654 | <path d={segOn} fill={p.secondary} fillOpacity={0.95} /> |
| 655 | − <Small x={cx} y={my + R * 0.16} text="ARTIFACT SCANNER · 7 / 12" color={p.secondary} size={R * 0.065} tracking="0.2em" opacity={0.85} /> | |
| 655 | + <Small x={cx} y={my + R * 0.15} text="ARTIFACT SCANNER · 7 / 12" color={p.secondary} size={R * 0.065} tracking="0.2em" opacity={0.85} /> | |
| 656 | 656 | </> |
| 657 | 657 | ) : null} |
| 658 | 658 | <path d={dust} fill={p.primary} fillOpacity={0.5} /> |
@@ -664,7 +664,7 @@ function PharaohProtocol(s: Stage) { | ||
| 664 | 664 | function LuckyCircuit(s: Stage) { |
| 665 | 665 | const { W, H, cx, cy, R, id, p, compact } = s; |
| 666 | 666 | const bw = R * 2.2; |
| 667 | − const bh = R * 2.05; | |
| 667 | + const bh = R * 1.9; | |
| 668 | 668 | const bx = cx - bw / 2; |
| 669 | 669 | const by = cy - bh / 2 - R * 0.05; |
| 670 | 670 | let scan = ""; |
@@ -698,13 +698,13 @@ function LuckyCircuit(s: Stage) { | ||
| 698 | 698 | <Sym s={s} id="MY" x={cx} y={cy - R * 0.08} size={R * 1.0} /> |
| 699 | 699 | {!compact ? ( |
| 700 | 700 | <> |
| 701 | − <Sym s={s} id="W" x={cx - R * 0.78} y={cy - R * 0.72} size={R * 0.48} rotate={-12} /> | |
| 702 | − <Sym s={s} id="P1" x={cx + R * 0.78} y={cy - R * 0.72} size={R * 0.48} rotate={10} /> | |
| 701 | + <Sym s={s} id="W" x={cx - R * 0.78} y={cy - R * 0.5} size={R * 0.48} rotate={-12} /> | |
| 702 | + <Sym s={s} id="P1" x={cx + R * 0.78} y={cy - R * 0.5} size={R * 0.48} rotate={10} /> | |
| 703 | 703 | <Sym s={s} id="H1" x={cx - R * 0.78} y={cy + R * 0.6} size={R * 0.46} /> |
| 704 | 704 | <Sym s={s} id="M2" x={cx + R * 0.78} y={cy + R * 0.6} size={R * 0.46} /> |
| 705 | 705 | <Sym s={s} id="S" x={cx} y={cy + R * 0.72} size={R * 0.38} /> |
| 706 | − <rect x={f(cx - R * 0.55)} y={f(by - R * 0.42)} width={f(R * 1.1)} height={f(R * 0.24)} rx={f(R * 0.05)} fill={p.glow} /> | |
| 707 | − <Small x={cx} y={by - R * 0.3} text="INSERT COIN" color="#fff" size={R * 0.1} weight={800} tracking="0.2em" /> | |
| 706 | + <rect x={f(cx - R * 0.55)} y={f(by + R * 0.06)} width={f(R * 1.1)} height={f(R * 0.24)} rx={f(R * 0.05)} fill={p.glow} /> | |
| 707 | + <Small x={cx} y={by + R * 0.18} text="INSERT COIN" color="#fff" size={R * 0.1} weight={800} tracking="0.2em" /> | |
| 708 | 708 | </> |
| 709 | 709 | ) : null} |
| 710 | 710 | </g> |
@@ -731,8 +731,8 @@ function VoidMiner(s: Stage) { | ||
| 731 | 731 | [cx + R * 0.7, cy + R * 0.95, R * 0.3, 8], |
| 732 | 732 | [cx - R * 0.15, cy - R * 1.12, R * 0.16, 7], |
| 733 | 733 | ] as const; |
| 734 | − const drillX = cx + R * 0.72; | |
| 735 | − const drillY = cy - R * 0.72; | |
| 734 | + const drillX = cx + R * 0.6; | |
| 735 | + const drillY = cy - R * 0.58; | |
| 736 | 736 | const circ = 2 * PI * R * 0.66; |
| 737 | 737 | const seg = circ / 5; |
| 738 | 738 | return ( |
@@ -755,8 +755,8 @@ function VoidMiner(s: Stage) { | ||
| 755 | 755 | <line x1={f(drillX)} y1={f(drillY)} x2={f(cx + R * 1.0)} y2={f(cy - R * 0.2)} stroke={p.secondary} strokeWidth={2} strokeOpacity={0.9} strokeDasharray="6 4" /> |
| 756 | 756 | <Sym s={s} id="W" x={drillX} y={drillY} size={R * 0.56} rotate={30} /> |
| 757 | 757 | <Sym s={s} id="P1" x={cx - R * 0.72} y={cy - R * 0.5} size={R * 0.56} /> |
| 758 | − <Sym s={s} id="H1" x={cx - R * 0.55} y={cy + R * 0.82} size={R * 0.44} /> | |
| 759 | − <Sym s={s} id="H2" x={cx + R * 0.15} y={cy + R * 0.95} size={R * 0.4} /> | |
| 758 | + <Sym s={s} id="H1" x={cx - R * 0.55} y={cy + R * 0.8} size={R * 0.44} /> | |
| 759 | + <Sym s={s} id="H2" x={cx + R * 0.2} y={cy + R * 0.82} size={R * 0.4} /> | |
| 760 | 760 | <Small x={cx + R * 0.02} y={cy - R * 0.98} text="CORE LV 3 / 5" color={p.secondary} size={R * 0.075} tracking="0.2em" weight={700} /> |
| 761 | 761 | <Small x={cx + R * 1.12} y={cy + R * 0.4} text="×1 ×2 ×3 ×4 ×5" color={p.primary} size={R * 0.07} tracking="0.16em" rotate={-90} opacity={0.75} /> |
| 762 | 762 | </> |
@@ -796,7 +796,7 @@ function RoyalCircuit(s: Stage) { | ||
| 796 | 796 | <path d={track} stroke="#1d1d26" strokeWidth={f(R * 0.56)} fill="none" strokeLinecap="round" /> |
| 797 | 797 | <path d={track} stroke="#fff" strokeOpacity={0.35} strokeWidth={2} fill="none" strokeDasharray="14 18" /> |
| 798 | 798 | <path d={streaks} stroke={p.primary} strokeOpacity={0.55} strokeWidth={2} strokeLinecap="round" /> |
| 799 | − <rect x={f(cx - R * 1.3)} y={f(cy + R * 1.02)} width={f(R * 2.6)} height={f(R * 0.16)} fill={`url(#${id}-rc0)`} /> | |
| 799 | + <rect x={f(cx - R * 1.3)} y={f(cy + R * 0.9)} width={f(R * 2.6)} height={f(R * 0.14)} fill={`url(#${id}-rc0)`} /> | |
| 800 | 800 | <Sym s={s} id="W" x={cx + R * 0.1} y={cy + R * 0.08} size={R * 0.96} rotate={-10} /> |
| 801 | 801 | {!compact ? ( |
| 802 | 802 | <> |
@@ -831,7 +831,7 @@ function DragonCore(s: Stage) { | ||
| 831 | 831 | const scales = [ |
| 832 | 832 | { x: cx + R * 0.95, y: cy + R * 0.45, r: 15 }, |
| 833 | 833 | { x: cx + R * 0.72, y: cy + R * 0.8, r: 30 }, |
| 834 | − { x: cx + R * 0.35, y: cy + R * 1.0, r: 45 }, | |
| 834 | + { x: cx + R * 0.4, y: cy + R * 0.8, r: 45 }, | |
| 835 | 835 | ]; |
| 836 | 836 | return ( |
| 837 | 837 | <g> |
@@ -854,7 +854,7 @@ function DragonCore(s: Stage) { | ||
| 854 | 854 | <Sym s={s} id="W" x={cx - R * 0.9} y={cy + R * 0.7} size={R * 0.56} rotate={-12} /> |
| 855 | 855 | <Sym s={s} id="S" x={cx - R * 0.95} y={cy - R * 0.75} size={R * 0.42} /> |
| 856 | 856 | <Sym s={s} id="H1" x={cx + R * 0.95} y={cy - R * 0.75} size={R * 0.42} /> |
| 857 | − <Small x={cx} y={cy + R * 1.24} text="DRAGON CHARGE 13 / 20" color={p.secondary} size={R * 0.075} tracking="0.2em" weight={700} opacity={0.9} /> | |
| 857 | + <Small x={cx} y={cy + R * 1.0} text="DRAGON CHARGE 13 / 20" color={p.secondary} size={R * 0.075} tracking="0.2em" weight={700} opacity={0.9} /> | |
| 858 | 858 | </> |
| 859 | 859 | ) : null} |
| 860 | 860 | <path d={embers} fill={p.secondary} fillOpacity={0.75} /> |
@@ -869,7 +869,7 @@ function DeepTreasure(s: Stage) { | ||
| 869 | 869 | for (let i = 0; i < 26; i++) bubbles.push([s.rnd() * W, cy - R * 1.3 + s.rnd() * R * 2.6, 2 + s.rnd() * R * 0.04]); |
| 870 | 870 | const levels = ["×1", "×2", "×3", "×4", "×6", "×8", "×10"]; |
| 871 | 871 | const top = cy - R * 1.05; |
| 872 | − const lh = R * 0.36; | |
| 872 | + const lh = R * 0.3; | |
| 873 | 873 | const chest = (x: number, y: number, w: number, key: string) => ( |
| 874 | 874 | <g key={key}> |
| 875 | 875 | <rect x={f(x - w / 2)} y={f(y - w * 0.28)} width={f(w)} height={f(w * 0.62)} rx={f(w * 0.06)} fill="#7a4a12" stroke="#fbbf24" strokeWidth={1.5} /> |
@@ -896,7 +896,7 @@ function DeepTreasure(s: Stage) { | ||
| 896 | 896 | : null} |
| 897 | 897 | {!compact ? chest(cx - R * 0.78, cy - R * 0.5, R * 0.42, "c1") : null} |
| 898 | 898 | {!compact ? chest(cx - R * 0.3, cy + R * 0.15, R * 0.5, "c2") : null} |
| 899 | − {chest(cx + R * 0.3, cy + R * 0.85, R * 0.6, "c3")} | |
| 899 | + {chest(cx + R * 0.3, cy + R * 0.72, R * 0.6, "c3")} | |
| 900 | 900 | <Sym s={s} id="P1" x={cx + R * 0.3} y={cy + R * 0.2} size={R * 0.9} /> |
| 901 | 901 | {!compact ? ( |
| 902 | 902 | <> |
@@ -1007,7 +1007,7 @@ function WildTemple(s: Stage) { | ||
| 1007 | 1007 | <Sym s={s} id="H1" x={cx + R * 0.98} y={cy + R * 0.62} size={R * 0.5} /> |
| 1008 | 1008 | <Sym s={s} id="H2" x={cx - R * 1.05} y={cy - R * 0.45} size={R * 0.4} /> |
| 1009 | 1009 | <Sym s={s} id="H2" x={cx + R * 1.05} y={cy - R * 0.45} size={R * 0.4} /> |
| 1010 | − <Sym s={s} id="M1" x={cx + R * 0.5} y={cy + R * 1.0} size={R * 0.34} rotate={30} /> | |
| 1010 | + <Sym s={s} id="M1" x={cx + R * 0.55} y={cy + R * 0.85} size={R * 0.34} rotate={30} /> | |
| 1011 | 1011 | </> |
| 1012 | 1012 | ) : null} |
| 1013 | 1013 | <path d={motes} fill={p.secondary} fillOpacity={0.55} /> |
@@ -1057,7 +1057,7 @@ function ZeroGravity(s: Stage) { | ||
| 1057 | 1057 | <Sym s={s} id="P1" x={cx - R * 0.95} y={cy + R * 0.02} size={R * 0.48} /> |
| 1058 | 1058 | <Sym s={s} id="S" x={cx + R * 1.05} y={cy + R * 0.42} size={R * 0.42} /> |
| 1059 | 1059 | <Sym s={s} id="H2" x={cx + R * 0.02} y={cy - R * 1.12} size={R * 0.38} rotate={12} /> |
| 1060 | − <Sym s={s} id="M1" x={cx + R * 0.98} y={cy + R * 1.0} size={R * 0.34} rotate={-30} /> | |
| 1060 | + <Sym s={s} id="M1" x={cx + R * 1.0} y={cy + R * 0.85} size={R * 0.34} rotate={-30} /> | |
| 1061 | 1061 | </> |
| 1062 | 1062 | ) : null} |
| 1063 | 1063 | </g> |
@@ -1073,7 +1073,7 @@ function ReelReactor(s: Stage) { | ||
| 1073 | 1073 | const at = (t: number) => a0 + (a1 - a0) * t; |
| 1074 | 1074 | const needle = at(0.72); |
| 1075 | 1075 | let hazard = ""; |
| 1076 | − const hy = cy + R * 1.08; | |
| 1076 | + const hy = cy + R * 0.95; | |
| 1077 | 1077 | for (let x = -R * 0.3; x < W + R; x += R * 0.22) hazard += `M${f(x)} ${f(hy)}h${f(R * 0.11)}l${f(-R * 0.1)} ${f(R * 0.12)}h${f(-R * 0.11)}z `; |
| 1078 | 1078 | const tick = (t: number, label: string, color: string) => { |
| 1079 | 1079 | const a = at(t); |
@@ -1096,7 +1096,7 @@ function ReelReactor(s: Stage) { | ||
| 1096 | 1096 | {!compact ? ( |
| 1097 | 1097 | <> |
| 1098 | 1098 | <Small x={cx} y={cy + R * 0.62} text="HEAT 72" color={p.secondary} size={R * 0.12} weight={800} tracking="0.06em" /> |
| 1099 | − <Pill x={cx + R * 0.72} y={cy - R * 1.1} text="MELTDOWN" color="#ef4444" ink="#ff8a8a" bg="#2a0808" size={R * 0.07} /> | |
| 1099 | + <Pill x={cx + R * 0.1} y={cy - R * 1.12} text="MELTDOWN" color="#ef4444" ink="#ff8a8a" bg="#2a0808" size={R * 0.07} /> | |
| 1100 | 1100 | <Sym s={s} id="W" x={cx - R * 0.9} y={cy + R * 0.62} size={R * 0.5} /> |
| 1101 | 1101 | <Sym s={s} id="S" x={cx + R * 0.9} y={cy + R * 0.62} size={R * 0.5} rotate={15} /> |
| 1102 | 1102 | <Sym s={s} id="H1" x={cx - R * 1.05} y={cy - R * 0.55} size={R * 0.4} /> |
@@ -1157,16 +1157,16 @@ function SpinzaOriginal(s: Stage) { | ||
| 1157 | 1157 | <Sym s={s} id="W" x={cx} y={cy} size={R * 0.9} plate={false} /> |
| 1158 | 1158 | {!compact ? ( |
| 1159 | 1159 | <> |
| 1160 | − <Small x={cx} y={cy + R * 0.98} text="MEGA METER 19 / 30" color={p.glow} size={R * 0.07} tracking="0.22em" weight={700} opacity={0.9} /> | |
| 1160 | + <Small x={cx} y={cy + R * 0.9} text="MEGA METER 19 / 30" color={p.glow} size={R * 0.07} tracking="0.22em" weight={700} opacity={0.9} /> | |
| 1161 | 1161 | <Sym s={s} id="MY" x={cx - R * 0.98} y={cy - R * 0.62} size={R * 0.62} /> |
| 1162 | 1162 | <Sym s={s} id="Z" x={cx - R * 0.98} y={cy + R * 0.3} size={R * 0.5} /> |
| 1163 | − <rect x={f(colX - R * 0.26)} y={f(cy - R * 1.25)} width={f(R * 0.52)} height={f(R * 2.4)} rx={f(R * 0.05)} fill="#fff" fillOpacity={0.04} stroke="#fff" strokeOpacity={0.12} /> | |
| 1163 | + <rect x={f(colX - R * 0.26)} y={f(cy - R * 1.12)} width={f(R * 0.52)} height={f(R * 2.12)} rx={f(R * 0.05)} fill="#fff" fillOpacity={0.04} stroke="#fff" strokeOpacity={0.12} /> | |
| 1164 | 1164 | {fall.map((idd, i) => ( |
| 1165 | 1165 | <Sym key={idd} s={s} id={idd} x={colX} y={cy - R * 0.95 + i * R * 0.56} size={R * 0.46} opacity={0.55 + i * 0.15} /> |
| 1166 | 1166 | ))} |
| 1167 | − <Pill x={cx - R * 0.5} y={cy - R * 1.18} text="WILD DROP" color={p.secondary} ink={p.secondary} size={R * 0.065} /> | |
| 1168 | − <Pill x={cx + R * 0.3} y={cy - R * 1.18} text="MULTIPLIER DROP" color={p.glow} ink={p.glow} size={R * 0.065} /> | |
| 1169 | − <Small x={cx} y={cy + R * 1.2} text="×1 ×2 ×3 ×4 ×6 ×8 ×10 ×15" color={p.primary} size={R * 0.07} tracking="0.16em" opacity={0.7} /> | |
| 1167 | + <Pill x={cx - R * 0.28} y={cy - R * 1.04} text="WILD DROP" color={p.secondary} ink={p.secondary} size={R * 0.065} /> | |
| 1168 | + <Pill x={cx + R * 0.44} y={cy - R * 1.04} text="MULTIPLIER DROP" color={p.glow} ink={p.glow} size={R * 0.065} /> | |
| 1169 | + <Small x={cx} y={cy + R * 1.02} text="×1 ×2 ×3 ×4 ×6 ×8 ×10 ×15" color={p.primary} size={R * 0.07} tracking="0.16em" opacity={0.7} /> | |
| 1170 | 1170 | </> |
| 1171 | 1171 | ) : null} |
| 1172 | 1172 | </g> |
@@ -1308,13 +1308,13 @@ function Title({ s, name, showName }: { s: Stage; name: string; showName: boolea | ||
| 1308 | 1308 | const eyebrow = spec.eyebrow && cfg.eye > 0 && v !== "tile"; |
| 1309 | 1309 | const eyeSize = v === "hero" ? size * 0.14 : v === "banner" ? size * 0.15 : Math.max(9.5, size * 0.2); |
| 1310 | 1310 | const fontStyle: React.CSSProperties = { fontFamily: FONT, letterSpacing: `${tracking}em` }; |
| 1311 | − const transform = spec.skew ? `skewX(${spec.skew})` : undefined; | |
| 1312 | 1311 | |
| 1313 | 1312 | const render = (props: React.SVGProps<SVGTextElement>, key: string) => |
| 1314 | 1313 | lines.map((l, i) => { |
| 1315 | 1314 | const isSub = spec.subline && i === 1; |
| 1316 | 1315 | const y = isSub ? baseY + subSize * 1.7 : baseY + i * lineH; |
| 1317 | 1316 | const base: React.CSSProperties = isSub ? { fontFamily: FONT, letterSpacing: "0.32em" } : fontStyle; |
| 1317 | + const transform = spec.skew ? `translate(${f(x)} ${f(y)}) skewX(${spec.skew}) translate(${f(-x)} ${f(-y)})` : undefined; | |
| 1318 | 1318 | return ( |
| 1319 | 1319 | <text key={`${key}${i}`} x={f(x)} y={f(y)} textAnchor={anchor} fontSize={f(isSub ? subSize : size)} fontWeight={isSub ? 700 : weight} transform={transform} {...props} style={{ ...base, ...props.style }}> |
| 1320 | 1320 | {l} |
added
games/certifications/bank-heist.json
+299 −0
@@ -0,0 +1,299 @@ | ||
| 1 | +{ | |
| 2 | + "game": "bank-heist", | |
| 3 | + "name": "Bank Heist", | |
| 4 | + "version": "1.0.0", | |
| 5 | + "spins": 2000000, | |
| 6 | + "configuredRtp": 0.96, | |
| 7 | + "observedRtp": 0.96391712, | |
| 8 | + "deviation": 0.003917119999999996, | |
| 9 | + "hitRate": 0.222629, | |
| 10 | + "bonusRate": 0, | |
| 11 | + "freeSpinRate": 0, | |
| 12 | + "maxWinMultiplier": 490.31, | |
| 13 | + "stdDev": 4.352455250737556, | |
| 14 | + "status": "PASS", | |
| 15 | + "checks": [ | |
| 16 | + { | |
| 17 | + "name": "definition", | |
| 18 | + "pass": true, | |
| 19 | + "detail": "rtp 0.96, cap 2500×" | |
| 20 | + }, | |
| 21 | + { | |
| 22 | + "name": "spins", | |
| 23 | + "pass": true, | |
| 24 | + "detail": "2,000,000 rounds" | |
| 25 | + }, | |
| 26 | + { | |
| 27 | + "name": "rtp-deviation", | |
| 28 | + "pass": true, | |
| 29 | + "detail": "0.392% (tolerance ±0.92%)" | |
| 30 | + }, | |
| 31 | + { | |
| 32 | + "name": "rtp-band", | |
| 33 | + "pass": true, | |
| 34 | + "detail": "96.39%" | |
| 35 | + }, | |
| 36 | + { | |
| 37 | + "name": "max-win", | |
| 38 | + "pass": true, | |
| 39 | + "detail": "490.3× (cap 2500×)" | |
| 40 | + }, | |
| 41 | + { | |
| 42 | + "name": "commitment", | |
| 43 | + "pass": true, | |
| 44 | + "detail": "SHA-256 commit/reveal verified" | |
| 45 | + } | |
| 46 | + ], | |
| 47 | + "certifiedAt": "2026-09-08T02:54:39.538Z", | |
| 48 | + "rules": { | |
| 49 | + "maxDeviation": 0.004, | |
| 50 | + "minSpins": 1000000, | |
| 51 | + "rtpBand": [ | |
| 52 | + 0.93, | |
| 53 | + 0.99 | |
| 54 | + ], | |
| 55 | + "hitRateBand": [ | |
| 56 | + 0.08, | |
| 57 | + 0.6 | |
| 58 | + ], | |
| 59 | + "maxCappedShare": 0.0005 | |
| 60 | + }, | |
| 61 | + "distribution": [ | |
| 62 | + { | |
| 63 | + "label": "0×", | |
| 64 | + "min": 0, | |
| 65 | + "max": 0, | |
| 66 | + "count": 1554742, | |
| 67 | + "share": 0.777371 | |
| 68 | + }, | |
| 69 | + { | |
| 70 | + "label": "1–1.5×", | |
| 71 | + "min": 1, | |
| 72 | + "max": 1.5, | |
| 73 | + "count": 135679, | |
| 74 | + "share": 0.0678395 | |
| 75 | + }, | |
| 76 | + { | |
| 77 | + "label": "1.5–2×", | |
| 78 | + "min": 1.5, | |
| 79 | + "max": 2, | |
| 80 | + "count": 79436, | |
| 81 | + "share": 0.039718 | |
| 82 | + }, | |
| 83 | + { | |
| 84 | + "label": "2–5×", | |
| 85 | + "min": 2, | |
| 86 | + "max": 5, | |
| 87 | + "count": 143327, | |
| 88 | + "share": 0.0716635 | |
| 89 | + }, | |
| 90 | + { | |
| 91 | + "label": "5–10×", | |
| 92 | + "min": 5, | |
| 93 | + "max": 10, | |
| 94 | + "count": 47641, | |
| 95 | + "share": 0.0238205 | |
| 96 | + }, | |
| 97 | + { | |
| 98 | + "label": "10–20×", | |
| 99 | + "min": 10, | |
| 100 | + "max": 20, | |
| 101 | + "count": 23971, | |
| 102 | + "share": 0.0119855 | |
| 103 | + }, | |
| 104 | + { | |
| 105 | + "label": "20–50×", | |
| 106 | + "min": 20, | |
| 107 | + "max": 50, | |
| 108 | + "count": 14602, | |
| 109 | + "share": 0.007301 | |
| 110 | + }, | |
| 111 | + { | |
| 112 | + "label": "50–100×", | |
| 113 | + "min": 50, | |
| 114 | + "max": 100, | |
| 115 | + "count": 346, | |
| 116 | + "share": 0.000173 | |
| 117 | + }, | |
| 118 | + { | |
| 119 | + "label": "100–500×", | |
| 120 | + "min": 100, | |
| 121 | + "max": 500, | |
| 122 | + "count": 256, | |
| 123 | + "share": 0.000128 | |
| 124 | + }, | |
| 125 | + { | |
| 126 | + "label": "500×+", | |
| 127 | + "min": 500, | |
| 128 | + "max": null, | |
| 129 | + "count": 0, | |
| 130 | + "share": 0 | |
| 131 | + } | |
| 132 | + ], | |
| 133 | + "convergence": [ | |
| 134 | + { | |
| 135 | + "spins": 50000, | |
| 136 | + "rtp": 0.9390514 | |
| 137 | + }, | |
| 138 | + { | |
| 139 | + "spins": 100000, | |
| 140 | + "rtp": 0.9494347 | |
| 141 | + }, | |
| 142 | + { | |
| 143 | + "spins": 150000, | |
| 144 | + "rtp": 0.9586966 | |
| 145 | + }, | |
| 146 | + { | |
| 147 | + "spins": 200000, | |
| 148 | + "rtp": 0.9608768 | |
| 149 | + }, | |
| 150 | + { | |
| 151 | + "spins": 250000, | |
| 152 | + "rtp": 0.96147524 | |
| 153 | + }, | |
| 154 | + { | |
| 155 | + "spins": 300000, | |
| 156 | + "rtp": 0.9642069666666667 | |
| 157 | + }, | |
| 158 | + { | |
| 159 | + "spins": 350000, | |
| 160 | + "rtp": 0.9594297714285714 | |
| 161 | + }, | |
| 162 | + { | |
| 163 | + "spins": 400000, | |
| 164 | + "rtp": 0.9628259 | |
| 165 | + }, | |
| 166 | + { | |
| 167 | + "spins": 450000, | |
| 168 | + "rtp": 0.9643958666666667 | |
| 169 | + }, | |
| 170 | + { | |
| 171 | + "spins": 500000, | |
| 172 | + "rtp": 0.96498998 | |
| 173 | + }, | |
| 174 | + { | |
| 175 | + "spins": 550000, | |
| 176 | + "rtp": 0.9642288181818182 | |
| 177 | + }, | |
| 178 | + { | |
| 179 | + "spins": 600000, | |
| 180 | + "rtp": 0.96441395 | |
| 181 | + }, | |
| 182 | + { | |
| 183 | + "spins": 650000, | |
| 184 | + "rtp": 0.9657298307692308 | |
| 185 | + }, | |
| 186 | + { | |
| 187 | + "spins": 700000, | |
| 188 | + "rtp": 0.9646824857142857 | |
| 189 | + }, | |
| 190 | + { | |
| 191 | + "spins": 750000, | |
| 192 | + "rtp": 0.9639896533333333 | |
| 193 | + }, | |
| 194 | + { | |
| 195 | + "spins": 800000, | |
| 196 | + "rtp": 0.9642843625 | |
| 197 | + }, | |
| 198 | + { | |
| 199 | + "spins": 850000, | |
| 200 | + "rtp": 0.9641510117647059 | |
| 201 | + }, | |
| 202 | + { | |
| 203 | + "spins": 900000, | |
| 204 | + "rtp": 0.9650899444444444 | |
| 205 | + }, | |
| 206 | + { | |
| 207 | + "spins": 950000, | |
| 208 | + "rtp": 0.965027852631579 | |
| 209 | + }, | |
| 210 | + { | |
| 211 | + "spins": 1000000, | |
| 212 | + "rtp": 0.96534183 | |
| 213 | + }, | |
| 214 | + { | |
| 215 | + "spins": 1050000, | |
| 216 | + "rtp": 0.9647746857142857 | |
| 217 | + }, | |
| 218 | + { | |
| 219 | + "spins": 1100000, | |
| 220 | + "rtp": 0.9648164636363636 | |
| 221 | + }, | |
| 222 | + { | |
| 223 | + "spins": 1150000, | |
| 224 | + "rtp": 0.9642805043478261 | |
| 225 | + }, | |
| 226 | + { | |
| 227 | + "spins": 1200000, | |
| 228 | + "rtp": 0.963466475 | |
| 229 | + }, | |
| 230 | + { | |
| 231 | + "spins": 1250000, | |
| 232 | + "rtp": 0.963158392 | |
| 233 | + }, | |
| 234 | + { | |
| 235 | + "spins": 1300000, | |
| 236 | + "rtp": 0.963437423076923 | |
| 237 | + }, | |
| 238 | + { | |
| 239 | + "spins": 1350000, | |
| 240 | + "rtp": 0.9637005703703704 | |
| 241 | + }, | |
| 242 | + { | |
| 243 | + "spins": 1400000, | |
| 244 | + "rtp": 0.9648829785714286 | |
| 245 | + }, | |
| 246 | + { | |
| 247 | + "spins": 1450000, | |
| 248 | + "rtp": 0.9652764551724138 | |
| 249 | + }, | |
| 250 | + { | |
| 251 | + "spins": 1500000, | |
| 252 | + "rtp": 0.9650323133333333 | |
| 253 | + }, | |
| 254 | + { | |
| 255 | + "spins": 1550000, | |
| 256 | + "rtp": 0.9638652967741935 | |
| 257 | + }, | |
| 258 | + { | |
| 259 | + "spins": 1600000, | |
| 260 | + "rtp": 0.96357528125 | |
| 261 | + }, | |
| 262 | + { | |
| 263 | + "spins": 1650000, | |
| 264 | + "rtp": 0.9641130666666666 | |
| 265 | + }, | |
| 266 | + { | |
| 267 | + "spins": 1700000, | |
| 268 | + "rtp": 0.9641277705882353 | |
| 269 | + }, | |
| 270 | + { | |
| 271 | + "spins": 1750000, | |
| 272 | + "rtp": 0.9643895371428571 | |
| 273 | + }, | |
| 274 | + { | |
| 275 | + "spins": 1800000, | |
| 276 | + "rtp": 0.9642674055555556 | |
| 277 | + }, | |
| 278 | + { | |
| 279 | + "spins": 1850000, | |
| 280 | + "rtp": 0.9640625027027027 | |
| 281 | + }, | |
| 282 | + { | |
| 283 | + "spins": 1900000, | |
| 284 | + "rtp": 0.9635775736842105 | |
| 285 | + }, | |
| 286 | + { | |
| 287 | + "spins": 1950000, | |
| 288 | + "rtp": 0.9641630205128205 | |
| 289 | + }, | |
| 290 | + { | |
| 291 | + "spins": 2000000, | |
| 292 | + "rtp": 0.96391712 | |
| 293 | + } | |
| 294 | + ], | |
| 295 | + "featureCounts": { | |
| 296 | + "Signal jammer": 600223 | |
| 297 | + }, | |
| 298 | + "durationMs": 134 | |
| 299 | +} | |
added
games/certifications/black-hole.json
+297 −0
@@ -0,0 +1,297 @@ | ||
| 1 | +{ | |
| 2 | + "game": "black-hole", | |
| 3 | + "name": "Black Hole", | |
| 4 | + "version": "1.0.0", | |
| 5 | + "spins": 2000000, | |
| 6 | + "configuredRtp": 0.96, | |
| 7 | + "observedRtp": 0.95368702, | |
| 8 | + "deviation": -0.0063129799999999126, | |
| 9 | + "hitRate": 0.2224205, | |
| 10 | + "bonusRate": 0, | |
| 11 | + "freeSpinRate": 0, | |
| 12 | + "maxWinMultiplier": 489.78, | |
| 13 | + "stdDev": 4.167256251226399, | |
| 14 | + "status": "PASS", | |
| 15 | + "checks": [ | |
| 16 | + { | |
| 17 | + "name": "definition", | |
| 18 | + "pass": true, | |
| 19 | + "detail": "rtp 0.96, cap 10000×" | |
| 20 | + }, | |
| 21 | + { | |
| 22 | + "name": "spins", | |
| 23 | + "pass": true, | |
| 24 | + "detail": "2,000,000 rounds" | |
| 25 | + }, | |
| 26 | + { | |
| 27 | + "name": "rtp-deviation", | |
| 28 | + "pass": true, | |
| 29 | + "detail": "-0.631% (tolerance ±0.88%)" | |
| 30 | + }, | |
| 31 | + { | |
| 32 | + "name": "rtp-band", | |
| 33 | + "pass": true, | |
| 34 | + "detail": "95.37%" | |
| 35 | + }, | |
| 36 | + { | |
| 37 | + "name": "max-win", | |
| 38 | + "pass": true, | |
| 39 | + "detail": "489.8× (cap 10000×)" | |
| 40 | + }, | |
| 41 | + { | |
| 42 | + "name": "commitment", | |
| 43 | + "pass": true, | |
| 44 | + "detail": "SHA-256 commit/reveal verified" | |
| 45 | + } | |
| 46 | + ], | |
| 47 | + "certifiedAt": "2026-09-08T02:54:39.773Z", | |
| 48 | + "rules": { | |
| 49 | + "maxDeviation": 0.004, | |
| 50 | + "minSpins": 1000000, | |
| 51 | + "rtpBand": [ | |
| 52 | + 0.93, | |
| 53 | + 0.99 | |
| 54 | + ], | |
| 55 | + "hitRateBand": [ | |
| 56 | + 0.08, | |
| 57 | + 0.6 | |
| 58 | + ], | |
| 59 | + "maxCappedShare": 0.0005 | |
| 60 | + }, | |
| 61 | + "distribution": [ | |
| 62 | + { | |
| 63 | + "label": "0×", | |
| 64 | + "min": 0, | |
| 65 | + "max": 0, | |
| 66 | + "count": 1555159, | |
| 67 | + "share": 0.7775795 | |
| 68 | + }, | |
| 69 | + { | |
| 70 | + "label": "1–1.5×", | |
| 71 | + "min": 1, | |
| 72 | + "max": 1.5, | |
| 73 | + "count": 136143, | |
| 74 | + "share": 0.0680715 | |
| 75 | + }, | |
| 76 | + { | |
| 77 | + "label": "1.5–2×", | |
| 78 | + "min": 1.5, | |
| 79 | + "max": 2, | |
| 80 | + "count": 79553, | |
| 81 | + "share": 0.0397765 | |
| 82 | + }, | |
| 83 | + { | |
| 84 | + "label": "2–5×", | |
| 85 | + "min": 2, | |
| 86 | + "max": 5, | |
| 87 | + "count": 142705, | |
| 88 | + "share": 0.0713525 | |
| 89 | + }, | |
| 90 | + { | |
| 91 | + "label": "5–10×", | |
| 92 | + "min": 5, | |
| 93 | + "max": 10, | |
| 94 | + "count": 47848, | |
| 95 | + "share": 0.023924 | |
| 96 | + }, | |
| 97 | + { | |
| 98 | + "label": "10–20×", | |
| 99 | + "min": 10, | |
| 100 | + "max": 20, | |
| 101 | + "count": 23848, | |
| 102 | + "share": 0.011924 | |
| 103 | + }, | |
| 104 | + { | |
| 105 | + "label": "20–50×", | |
| 106 | + "min": 20, | |
| 107 | + "max": 50, | |
| 108 | + "count": 14190, | |
| 109 | + "share": 0.007095 | |
| 110 | + }, | |
| 111 | + { | |
| 112 | + "label": "50–100×", | |
| 113 | + "min": 50, | |
| 114 | + "max": 100, | |
| 115 | + "count": 312, | |
| 116 | + "share": 0.000156 | |
| 117 | + }, | |
| 118 | + { | |
| 119 | + "label": "100–500×", | |
| 120 | + "min": 100, | |
| 121 | + "max": 500, | |
| 122 | + "count": 242, | |
| 123 | + "share": 0.000121 | |
| 124 | + }, | |
| 125 | + { | |
| 126 | + "label": "500×+", | |
| 127 | + "min": 500, | |
| 128 | + "max": null, | |
| 129 | + "count": 0, | |
| 130 | + "share": 0 | |
| 131 | + } | |
| 132 | + ], | |
| 133 | + "convergence": [ | |
| 134 | + { | |
| 135 | + "spins": 50000, | |
| 136 | + "rtp": 0.921937 | |
| 137 | + }, | |
| 138 | + { | |
| 139 | + "spins": 100000, | |
| 140 | + "rtp": 0.9377734 | |
| 141 | + }, | |
| 142 | + { | |
| 143 | + "spins": 150000, | |
| 144 | + "rtp": 0.9353091333333333 | |
| 145 | + }, | |
| 146 | + { | |
| 147 | + "spins": 200000, | |
| 148 | + "rtp": 0.93739225 | |
| 149 | + }, | |
| 150 | + { | |
| 151 | + "spins": 250000, | |
| 152 | + "rtp": 0.93914564 | |
| 153 | + }, | |
| 154 | + { | |
| 155 | + "spins": 300000, | |
| 156 | + "rtp": 0.9347733 | |
| 157 | + }, | |
| 158 | + { | |
| 159 | + "spins": 350000, | |
| 160 | + "rtp": 0.9388381714285714 | |
| 161 | + }, | |
| 162 | + { | |
| 163 | + "spins": 400000, | |
| 164 | + "rtp": 0.943534225 | |
| 165 | + }, | |
| 166 | + { | |
| 167 | + "spins": 450000, | |
| 168 | + "rtp": 0.9437072 | |
| 169 | + }, | |
| 170 | + { | |
| 171 | + "spins": 500000, | |
| 172 | + "rtp": 0.94537304 | |
| 173 | + }, | |
| 174 | + { | |
| 175 | + "spins": 550000, | |
| 176 | + "rtp": 0.9467291818181818 | |
| 177 | + }, | |
| 178 | + { | |
| 179 | + "spins": 600000, | |
| 180 | + "rtp": 0.9489026 | |
| 181 | + }, | |
| 182 | + { | |
| 183 | + "spins": 650000, | |
| 184 | + "rtp": 0.9520744923076923 | |
| 185 | + }, | |
| 186 | + { | |
| 187 | + "spins": 700000, | |
| 188 | + "rtp": 0.9523814285714286 | |
| 189 | + }, | |
| 190 | + { | |
| 191 | + "spins": 750000, | |
| 192 | + "rtp": 0.9508651866666666 | |
| 193 | + }, | |
| 194 | + { | |
| 195 | + "spins": 800000, | |
| 196 | + "rtp": 0.9510268375 | |
| 197 | + }, | |
| 198 | + { | |
| 199 | + "spins": 850000, | |
| 200 | + "rtp": 0.9504187294117648 | |
| 201 | + }, | |
| 202 | + { | |
| 203 | + "spins": 900000, | |
| 204 | + "rtp": 0.9504978555555555 | |
| 205 | + }, | |
| 206 | + { | |
| 207 | + "spins": 950000, | |
| 208 | + "rtp": 0.9502219052631579 | |
| 209 | + }, | |
| 210 | + { | |
| 211 | + "spins": 1000000, | |
| 212 | + "rtp": 0.95194051 | |
| 213 | + }, | |
| 214 | + { | |
| 215 | + "spins": 1050000, | |
| 216 | + "rtp": 0.9534165714285714 | |
| 217 | + }, | |
| 218 | + { | |
| 219 | + "spins": 1100000, | |
| 220 | + "rtp": 0.9541829 | |
| 221 | + }, | |
| 222 | + { | |
| 223 | + "spins": 1150000, | |
| 224 | + "rtp": 0.9539388086956522 | |
| 225 | + }, | |
| 226 | + { | |
| 227 | + "spins": 1200000, | |
| 228 | + "rtp": 0.9536442166666667 | |
| 229 | + }, | |
| 230 | + { | |
| 231 | + "spins": 1250000, | |
| 232 | + "rtp": 0.953784856 | |
| 233 | + }, | |
| 234 | + { | |
| 235 | + "spins": 1300000, | |
| 236 | + "rtp": 0.9539154615384615 | |
| 237 | + }, | |
| 238 | + { | |
| 239 | + "spins": 1350000, | |
| 240 | + "rtp": 0.9542466888888889 | |
| 241 | + }, | |
| 242 | + { | |
| 243 | + "spins": 1400000, | |
| 244 | + "rtp": 0.9538773285714286 | |
| 245 | + }, | |
| 246 | + { | |
| 247 | + "spins": 1450000, | |
| 248 | + "rtp": 0.9536818620689655 | |
| 249 | + }, | |
| 250 | + { | |
| 251 | + "spins": 1500000, | |
| 252 | + "rtp": 0.9545845466666667 | |
| 253 | + }, | |
| 254 | + { | |
| 255 | + "spins": 1550000, | |
| 256 | + "rtp": 0.9545137741935484 | |
| 257 | + }, | |
| 258 | + { | |
| 259 | + "spins": 1600000, | |
| 260 | + "rtp": 0.95469646875 | |
| 261 | + }, | |
| 262 | + { | |
| 263 | + "spins": 1650000, | |
| 264 | + "rtp": 0.9549692848484849 | |
| 265 | + }, | |
| 266 | + { | |
| 267 | + "spins": 1700000, | |
| 268 | + "rtp": 0.9543618882352941 | |
| 269 | + }, | |
| 270 | + { | |
| 271 | + "spins": 1750000, | |
| 272 | + "rtp": 0.9543698685714286 | |
| 273 | + }, | |
| 274 | + { | |
| 275 | + "spins": 1800000, | |
| 276 | + "rtp": 0.9543075722222222 | |
| 277 | + }, | |
| 278 | + { | |
| 279 | + "spins": 1850000, | |
| 280 | + "rtp": 0.9546324378378378 | |
| 281 | + }, | |
| 282 | + { | |
| 283 | + "spins": 1900000, | |
| 284 | + "rtp": 0.9546098052631579 | |
| 285 | + }, | |
| 286 | + { | |
| 287 | + "spins": 1950000, | |
| 288 | + "rtp": 0.9546309282051282 | |
| 289 | + }, | |
| 290 | + { | |
| 291 | + "spins": 2000000, | |
| 292 | + "rtp": 0.95368702 | |
| 293 | + } | |
| 294 | + ], | |
| 295 | + "featureCounts": {}, | |
| 296 | + "durationMs": 104 | |
| 297 | +} | |
added
games/certifications/core-meltdown.json
+300 −0
@@ -0,0 +1,300 @@ | ||
| 1 | +{ | |
| 2 | + "game": "core-meltdown", | |
| 3 | + "name": "Core Meltdown", | |
| 4 | + "version": "1.0.0", | |
| 5 | + "spins": 2000000, | |
| 6 | + "configuredRtp": 0.96, | |
| 7 | + "observedRtp": 0.954057215, | |
| 8 | + "deviation": -0.005942785000000006, | |
| 9 | + "hitRate": 0.223306, | |
| 10 | + "bonusRate": 0, | |
| 11 | + "freeSpinRate": 0, | |
| 12 | + "maxWinMultiplier": 494.09, | |
| 13 | + "stdDev": 4.097552547967906, | |
| 14 | + "status": "PASS", | |
| 15 | + "checks": [ | |
| 16 | + { | |
| 17 | + "name": "definition", | |
| 18 | + "pass": true, | |
| 19 | + "detail": "rtp 0.96, cap 5000×" | |
| 20 | + }, | |
| 21 | + { | |
| 22 | + "name": "spins", | |
| 23 | + "pass": true, | |
| 24 | + "detail": "2,000,000 rounds" | |
| 25 | + }, | |
| 26 | + { | |
| 27 | + "name": "rtp-deviation", | |
| 28 | + "pass": true, | |
| 29 | + "detail": "-0.594% (tolerance ±0.87%)" | |
| 30 | + }, | |
| 31 | + { | |
| 32 | + "name": "rtp-band", | |
| 33 | + "pass": true, | |
| 34 | + "detail": "95.41%" | |
| 35 | + }, | |
| 36 | + { | |
| 37 | + "name": "max-win", | |
| 38 | + "pass": true, | |
| 39 | + "detail": "494.1× (cap 5000×)" | |
| 40 | + }, | |
| 41 | + { | |
| 42 | + "name": "commitment", | |
| 43 | + "pass": true, | |
| 44 | + "detail": "SHA-256 commit/reveal verified" | |
| 45 | + } | |
| 46 | + ], | |
| 47 | + "certifiedAt": "2026-09-08T02:54:40.153Z", | |
| 48 | + "rules": { | |
| 49 | + "maxDeviation": 0.004, | |
| 50 | + "minSpins": 1000000, | |
| 51 | + "rtpBand": [ | |
| 52 | + 0.93, | |
| 53 | + 0.99 | |
| 54 | + ], | |
| 55 | + "hitRateBand": [ | |
| 56 | + 0.08, | |
| 57 | + 0.6 | |
| 58 | + ], | |
| 59 | + "maxCappedShare": 0.0005 | |
| 60 | + }, | |
| 61 | + "distribution": [ | |
| 62 | + { | |
| 63 | + "label": "0×", | |
| 64 | + "min": 0, | |
| 65 | + "max": 0, | |
| 66 | + "count": 1553388, | |
| 67 | + "share": 0.776694 | |
| 68 | + }, | |
| 69 | + { | |
| 70 | + "label": "1–1.5×", | |
| 71 | + "min": 1, | |
| 72 | + "max": 1.5, | |
| 73 | + "count": 136851, | |
| 74 | + "share": 0.0684255 | |
| 75 | + }, | |
| 76 | + { | |
| 77 | + "label": "1.5–2×", | |
| 78 | + "min": 1.5, | |
| 79 | + "max": 2, | |
| 80 | + "count": 79895, | |
| 81 | + "share": 0.0399475 | |
| 82 | + }, | |
| 83 | + { | |
| 84 | + "label": "2–5×", | |
| 85 | + "min": 2, | |
| 86 | + "max": 5, | |
| 87 | + "count": 143513, | |
| 88 | + "share": 0.0717565 | |
| 89 | + }, | |
| 90 | + { | |
| 91 | + "label": "5–10×", | |
| 92 | + "min": 5, | |
| 93 | + "max": 10, | |
| 94 | + "count": 47803, | |
| 95 | + "share": 0.0239015 | |
| 96 | + }, | |
| 97 | + { | |
| 98 | + "label": "10–20×", | |
| 99 | + "min": 10, | |
| 100 | + "max": 20, | |
| 101 | + "count": 23696, | |
| 102 | + "share": 0.011848 | |
| 103 | + }, | |
| 104 | + { | |
| 105 | + "label": "20–50×", | |
| 106 | + "min": 20, | |
| 107 | + "max": 50, | |
| 108 | + "count": 14316, | |
| 109 | + "share": 0.007158 | |
| 110 | + }, | |
| 111 | + { | |
| 112 | + "label": "50–100×", | |
| 113 | + "min": 50, | |
| 114 | + "max": 100, | |
| 115 | + "count": 331, | |
| 116 | + "share": 0.0001655 | |
| 117 | + }, | |
| 118 | + { | |
| 119 | + "label": "100–500×", | |
| 120 | + "min": 100, | |
| 121 | + "max": 500, | |
| 122 | + "count": 207, | |
| 123 | + "share": 0.0001035 | |
| 124 | + }, | |
| 125 | + { | |
| 126 | + "label": "500×+", | |
| 127 | + "min": 500, | |
| 128 | + "max": null, | |
| 129 | + "count": 0, | |
| 130 | + "share": 0 | |
| 131 | + } | |
| 132 | + ], | |
| 133 | + "convergence": [ | |
| 134 | + { | |
| 135 | + "spins": 50000, | |
| 136 | + "rtp": 0.947085 | |
| 137 | + }, | |
| 138 | + { | |
| 139 | + "spins": 100000, | |
| 140 | + "rtp": 0.9343246 | |
| 141 | + }, | |
| 142 | + { | |
| 143 | + "spins": 150000, | |
| 144 | + "rtp": 0.9442656666666667 | |
| 145 | + }, | |
| 146 | + { | |
| 147 | + "spins": 200000, | |
| 148 | + "rtp": 0.9465809 | |
| 149 | + }, | |
| 150 | + { | |
| 151 | + "spins": 250000, | |
| 152 | + "rtp": 0.94889528 | |
| 153 | + }, | |
| 154 | + { | |
| 155 | + "spins": 300000, | |
| 156 | + "rtp": 0.9459146 | |
| 157 | + }, | |
| 158 | + { | |
| 159 | + "spins": 350000, | |
| 160 | + "rtp": 0.9462324 | |
| 161 | + }, | |
| 162 | + { | |
| 163 | + "spins": 400000, | |
| 164 | + "rtp": 0.9444719 | |
| 165 | + }, | |
| 166 | + { | |
| 167 | + "spins": 450000, | |
| 168 | + "rtp": 0.9446777111111111 | |
| 169 | + }, | |
| 170 | + { | |
| 171 | + "spins": 500000, | |
| 172 | + "rtp": 0.94909574 | |
| 173 | + }, | |
| 174 | + { | |
| 175 | + "spins": 550000, | |
| 176 | + "rtp": 0.9501834909090909 | |
| 177 | + }, | |
| 178 | + { | |
| 179 | + "spins": 600000, | |
| 180 | + "rtp": 0.9498570166666667 | |
| 181 | + }, | |
| 182 | + { | |
| 183 | + "spins": 650000, | |
| 184 | + "rtp": 0.9506063692307692 | |
| 185 | + }, | |
| 186 | + { | |
| 187 | + "spins": 700000, | |
| 188 | + "rtp": 0.9512420714285714 | |
| 189 | + }, | |
| 190 | + { | |
| 191 | + "spins": 750000, | |
| 192 | + "rtp": 0.9517908133333334 | |
| 193 | + }, | |
| 194 | + { | |
| 195 | + "spins": 800000, | |
| 196 | + "rtp": 0.9524256 | |
| 197 | + }, | |
| 198 | + { | |
| 199 | + "spins": 850000, | |
| 200 | + "rtp": 0.9533394588235294 | |
| 201 | + }, | |
| 202 | + { | |
| 203 | + "spins": 900000, | |
| 204 | + "rtp": 0.9521214666666666 | |
| 205 | + }, | |
| 206 | + { | |
| 207 | + "spins": 950000, | |
| 208 | + "rtp": 0.9524753789473684 | |
| 209 | + }, | |
| 210 | + { | |
| 211 | + "spins": 1000000, | |
| 212 | + "rtp": 0.95258458 | |
| 213 | + }, | |
| 214 | + { | |
| 215 | + "spins": 1050000, | |
| 216 | + "rtp": 0.9535204666666667 | |
| 217 | + }, | |
| 218 | + { | |
| 219 | + "spins": 1100000, | |
| 220 | + "rtp": 0.9536495181818182 | |
| 221 | + }, | |
| 222 | + { | |
| 223 | + "spins": 1150000, | |
| 224 | + "rtp": 0.953184947826087 | |
| 225 | + }, | |
| 226 | + { | |
| 227 | + "spins": 1200000, | |
| 228 | + "rtp": 0.9544278333333334 | |
| 229 | + }, | |
| 230 | + { | |
| 231 | + "spins": 1250000, | |
| 232 | + "rtp": 0.954959856 | |
| 233 | + }, | |
| 234 | + { | |
| 235 | + "spins": 1300000, | |
| 236 | + "rtp": 0.954769376923077 | |
| 237 | + }, | |
| 238 | + { | |
| 239 | + "spins": 1350000, | |
| 240 | + "rtp": 0.9548739037037037 | |
| 241 | + }, | |
| 242 | + { | |
| 243 | + "spins": 1400000, | |
| 244 | + "rtp": 0.9549191928571429 | |
| 245 | + }, | |
| 246 | + { | |
| 247 | + "spins": 1450000, | |
| 248 | + "rtp": 0.9545073793103448 | |
| 249 | + }, | |
| 250 | + { | |
| 251 | + "spins": 1500000, | |
| 252 | + "rtp": 0.9543815066666667 | |
| 253 | + }, | |
| 254 | + { | |
| 255 | + "spins": 1550000, | |
| 256 | + "rtp": 0.9548629483870967 | |
| 257 | + }, | |
| 258 | + { | |
| 259 | + "spins": 1600000, | |
| 260 | + "rtp": 0.95486700625 | |
| 261 | + }, | |
| 262 | + { | |
| 263 | + "spins": 1650000, | |
| 264 | + "rtp": 0.9546481818181818 | |
| 265 | + }, | |
| 266 | + { | |
| 267 | + "spins": 1700000, | |
| 268 | + "rtp": 0.9551030529411765 | |
| 269 | + }, | |
| 270 | + { | |
| 271 | + "spins": 1750000, | |
| 272 | + "rtp": 0.9554977371428571 | |
| 273 | + }, | |
| 274 | + { | |
| 275 | + "spins": 1800000, | |
| 276 | + "rtp": 0.9563426055555555 | |
| 277 | + }, | |
| 278 | + { | |
| 279 | + "spins": 1850000, | |
| 280 | + "rtp": 0.9555952540540541 | |
| 281 | + }, | |
| 282 | + { | |
| 283 | + "spins": 1900000, | |
| 284 | + "rtp": 0.9547046315789474 | |
| 285 | + }, | |
| 286 | + { | |
| 287 | + "spins": 1950000, | |
| 288 | + "rtp": 0.9543590512820512 | |
| 289 | + }, | |
| 290 | + { | |
| 291 | + "spins": 2000000, | |
| 292 | + "rtp": 0.954057215 | |
| 293 | + } | |
| 294 | + ], | |
| 295 | + "featureCounts": { | |
| 296 | + "Power spike": 337235, | |
| 297 | + "Coolant surge": 1011023 | |
| 298 | + }, | |
| 299 | + "durationMs": 236 | |
| 300 | +} | |
added
games/certifications/deep-dive.json
+299 −0
@@ -0,0 +1,299 @@ | ||
| 1 | +{ | |
| 2 | + "game": "deep-dive", | |
| 3 | + "name": "Deep Dive", | |
| 4 | + "version": "1.0.0", | |
| 5 | + "spins": 2000000, | |
| 6 | + "configuredRtp": 0.96, | |
| 7 | + "observedRtp": 0.960874195, | |
| 8 | + "deviation": 0.0008741950000000775, | |
| 9 | + "hitRate": 0.2230625, | |
| 10 | + "bonusRate": 0, | |
| 11 | + "freeSpinRate": 0, | |
| 12 | + "maxWinMultiplier": 496.58, | |
| 13 | + "stdDev": 4.223505991227474, | |
| 14 | + "status": "PASS", | |
| 15 | + "checks": [ | |
| 16 | + { | |
| 17 | + "name": "definition", | |
| 18 | + "pass": true, | |
| 19 | + "detail": "rtp 0.96, cap 5000×" | |
| 20 | + }, | |
| 21 | + { | |
| 22 | + "name": "spins", | |
| 23 | + "pass": true, | |
| 24 | + "detail": "2,000,000 rounds" | |
| 25 | + }, | |
| 26 | + { | |
| 27 | + "name": "rtp-deviation", | |
| 28 | + "pass": true, | |
| 29 | + "detail": "0.087% (tolerance ±0.90%)" | |
| 30 | + }, | |
| 31 | + { | |
| 32 | + "name": "rtp-band", | |
| 33 | + "pass": true, | |
| 34 | + "detail": "96.09%" | |
| 35 | + }, | |
| 36 | + { | |
| 37 | + "name": "max-win", | |
| 38 | + "pass": true, | |
| 39 | + "detail": "496.6× (cap 5000×)" | |
| 40 | + }, | |
| 41 | + { | |
| 42 | + "name": "commitment", | |
| 43 | + "pass": true, | |
| 44 | + "detail": "SHA-256 commit/reveal verified" | |
| 45 | + } | |
| 46 | + ], | |
| 47 | + "certifiedAt": "2026-09-08T02:54:39.274Z", | |
| 48 | + "rules": { | |
| 49 | + "maxDeviation": 0.004, | |
| 50 | + "minSpins": 1000000, | |
| 51 | + "rtpBand": [ | |
| 52 | + 0.93, | |
| 53 | + 0.99 | |
| 54 | + ], | |
| 55 | + "hitRateBand": [ | |
| 56 | + 0.08, | |
| 57 | + 0.6 | |
| 58 | + ], | |
| 59 | + "maxCappedShare": 0.0005 | |
| 60 | + }, | |
| 61 | + "distribution": [ | |
| 62 | + { | |
| 63 | + "label": "0×", | |
| 64 | + "min": 0, | |
| 65 | + "max": 0, | |
| 66 | + "count": 1553875, | |
| 67 | + "share": 0.7769375 | |
| 68 | + }, | |
| 69 | + { | |
| 70 | + "label": "1–1.5×", | |
| 71 | + "min": 1, | |
| 72 | + "max": 1.5, | |
| 73 | + "count": 136388, | |
| 74 | + "share": 0.068194 | |
| 75 | + }, | |
| 76 | + { | |
| 77 | + "label": "1.5–2×", | |
| 78 | + "min": 1.5, | |
| 79 | + "max": 2, | |
| 80 | + "count": 79522, | |
| 81 | + "share": 0.039761 | |
| 82 | + }, | |
| 83 | + { | |
| 84 | + "label": "2–5×", | |
| 85 | + "min": 2, | |
| 86 | + "max": 5, | |
| 87 | + "count": 143328, | |
| 88 | + "share": 0.071664 | |
| 89 | + }, | |
| 90 | + { | |
| 91 | + "label": "5–10×", | |
| 92 | + "min": 5, | |
| 93 | + "max": 10, | |
| 94 | + "count": 47784, | |
| 95 | + "share": 0.023892 | |
| 96 | + }, | |
| 97 | + { | |
| 98 | + "label": "10–20×", | |
| 99 | + "min": 10, | |
| 100 | + "max": 20, | |
| 101 | + "count": 24199, | |
| 102 | + "share": 0.0120995 | |
| 103 | + }, | |
| 104 | + { | |
| 105 | + "label": "20–50×", | |
| 106 | + "min": 20, | |
| 107 | + "max": 50, | |
| 108 | + "count": 14322, | |
| 109 | + "share": 0.007161 | |
| 110 | + }, | |
| 111 | + { | |
| 112 | + "label": "50–100×", | |
| 113 | + "min": 50, | |
| 114 | + "max": 100, | |
| 115 | + "count": 327, | |
| 116 | + "share": 0.0001635 | |
| 117 | + }, | |
| 118 | + { | |
| 119 | + "label": "100–500×", | |
| 120 | + "min": 100, | |
| 121 | + "max": 500, | |
| 122 | + "count": 255, | |
| 123 | + "share": 0.0001275 | |
| 124 | + }, | |
| 125 | + { | |
| 126 | + "label": "500×+", | |
| 127 | + "min": 500, | |
| 128 | + "max": null, | |
| 129 | + "count": 0, | |
| 130 | + "share": 0 | |
| 131 | + } | |
| 132 | + ], | |
| 133 | + "convergence": [ | |
| 134 | + { | |
| 135 | + "spins": 50000, | |
| 136 | + "rtp": 0.981744 | |
| 137 | + }, | |
| 138 | + { | |
| 139 | + "spins": 100000, | |
| 140 | + "rtp": 0.9688415 | |
| 141 | + }, | |
| 142 | + { | |
| 143 | + "spins": 150000, | |
| 144 | + "rtp": 0.9660274666666666 | |
| 145 | + }, | |
| 146 | + { | |
| 147 | + "spins": 200000, | |
| 148 | + "rtp": 0.95946645 | |
| 149 | + }, | |
| 150 | + { | |
| 151 | + "spins": 250000, | |
| 152 | + "rtp": 0.95799912 | |
| 153 | + }, | |
| 154 | + { | |
| 155 | + "spins": 300000, | |
| 156 | + "rtp": 0.9605313 | |
| 157 | + }, | |
| 158 | + { | |
| 159 | + "spins": 350000, | |
| 160 | + "rtp": 0.9544169142857143 | |
| 161 | + }, | |
| 162 | + { | |
| 163 | + "spins": 400000, | |
| 164 | + "rtp": 0.956806225 | |
| 165 | + }, | |
| 166 | + { | |
| 167 | + "spins": 450000, | |
| 168 | + "rtp": 0.9591186222222222 | |
| 169 | + }, | |
| 170 | + { | |
| 171 | + "spins": 500000, | |
| 172 | + "rtp": 0.9582865 | |
| 173 | + }, | |
| 174 | + { | |
| 175 | + "spins": 550000, | |
| 176 | + "rtp": 0.9583992545454545 | |
| 177 | + }, | |
| 178 | + { | |
| 179 | + "spins": 600000, | |
| 180 | + "rtp": 0.9582501166666667 | |
| 181 | + }, | |
| 182 | + { | |
| 183 | + "spins": 650000, | |
| 184 | + "rtp": 0.9575540307692307 | |
| 185 | + }, | |
| 186 | + { | |
| 187 | + "spins": 700000, | |
| 188 | + "rtp": 0.9579928571428571 | |
| 189 | + }, | |
| 190 | + { | |
| 191 | + "spins": 750000, | |
| 192 | + "rtp": 0.9563829866666667 | |
| 193 | + }, | |
| 194 | + { | |
| 195 | + "spins": 800000, | |
| 196 | + "rtp": 0.956648 | |
| 197 | + }, | |
| 198 | + { | |
| 199 | + "spins": 850000, | |
| 200 | + "rtp": 0.9576155058823529 | |
| 201 | + }, | |
| 202 | + { | |
| 203 | + "spins": 900000, | |
| 204 | + "rtp": 0.9573925555555556 | |
| 205 | + }, | |
| 206 | + { | |
| 207 | + "spins": 950000, | |
| 208 | + "rtp": 0.9598498210526316 | |
| 209 | + }, | |
| 210 | + { | |
| 211 | + "spins": 1000000, | |
| 212 | + "rtp": 0.95725369 | |
| 213 | + }, | |
| 214 | + { | |
| 215 | + "spins": 1050000, | |
| 216 | + "rtp": 0.956701380952381 | |
| 217 | + }, | |
| 218 | + { | |
| 219 | + "spins": 1100000, | |
| 220 | + "rtp": 0.9588518727272727 | |
| 221 | + }, | |
| 222 | + { | |
| 223 | + "spins": 1150000, | |
| 224 | + "rtp": 0.9587854173913043 | |
| 225 | + }, | |
| 226 | + { | |
| 227 | + "spins": 1200000, | |
| 228 | + "rtp": 0.9592476833333333 | |
| 229 | + }, | |
| 230 | + { | |
| 231 | + "spins": 1250000, | |
| 232 | + "rtp": 0.959404616 | |
| 233 | + }, | |
| 234 | + { | |
| 235 | + "spins": 1300000, | |
| 236 | + "rtp": 0.9605161615384615 | |
| 237 | + }, | |
| 238 | + { | |
| 239 | + "spins": 1350000, | |
| 240 | + "rtp": 0.9614446666666666 | |
| 241 | + }, | |
| 242 | + { | |
| 243 | + "spins": 1400000, | |
| 244 | + "rtp": 0.9608630642857143 | |
| 245 | + }, | |
| 246 | + { | |
| 247 | + "spins": 1450000, | |
| 248 | + "rtp": 0.9613541931034483 | |
| 249 | + }, | |
| 250 | + { | |
| 251 | + "spins": 1500000, | |
| 252 | + "rtp": 0.9613371266666667 | |
| 253 | + }, | |
| 254 | + { | |
| 255 | + "spins": 1550000, | |
| 256 | + "rtp": 0.9614718967741935 | |
| 257 | + }, | |
| 258 | + { | |
| 259 | + "spins": 1600000, | |
| 260 | + "rtp": 0.9618734875 | |
| 261 | + }, | |
| 262 | + { | |
| 263 | + "spins": 1650000, | |
| 264 | + "rtp": 0.9609947878787879 | |
| 265 | + }, | |
| 266 | + { | |
| 267 | + "spins": 1700000, | |
| 268 | + "rtp": 0.961304194117647 | |
| 269 | + }, | |
| 270 | + { | |
| 271 | + "spins": 1750000, | |
| 272 | + "rtp": 0.9610557142857142 | |
| 273 | + }, | |
| 274 | + { | |
| 275 | + "spins": 1800000, | |
| 276 | + "rtp": 0.9604515166666666 | |
| 277 | + }, | |
| 278 | + { | |
| 279 | + "spins": 1850000, | |
| 280 | + "rtp": 0.960938627027027 | |
| 281 | + }, | |
| 282 | + { | |
| 283 | + "spins": 1900000, | |
| 284 | + "rtp": 0.9602719631578948 | |
| 285 | + }, | |
| 286 | + { | |
| 287 | + "spins": 1950000, | |
| 288 | + "rtp": 0.9605036974358975 | |
| 289 | + }, | |
| 290 | + { | |
| 291 | + "spins": 2000000, | |
| 292 | + "rtp": 0.960874195 | |
| 293 | + } | |
| 294 | + ], | |
| 295 | + "featureCounts": { | |
| 296 | + "Leviathan current": 900870 | |
| 297 | + }, | |
| 298 | + "durationMs": 180 | |
| 299 | +} | |
added
games/certifications/elevator-999.json
+297 −0
Large diff (297 lines) is not loaded by default to keep the page fast.Load diff
added
games/certifications/freefall.json
+299 −0
Large diff (299 lines) is not loaded by default to keep the page fast.Load diff
added
games/certifications/rocket-run.json
+299 −0
Large diff (299 lines) is not loaded by default to keep the page fast.Load diff
added
games/certifications/skyfall.json
+299 −0
Large diff (299 lines) is not loaded by default to keep the page fast.Load diff
added
games/certifications/storm-chase.json
+299 −0
Large diff (299 lines) is not loaded by default to keep the page fast.Load diff
added
games/certifications/volcano.json
+299 −0
Large diff (299 lines) is not loaded by default to keep the page fast.Load diff
modified
games/src/client.ts
+1 −0
Large diff (4 lines) is not loaded by default to keep the page fast.Load diff
added
games/src/crash/index.ts
+238 −0
Large diff (238 lines) is not loaded by default to keep the page fast.Load diff
modified
games/src/index.ts
+1 −0
Large diff (4 lines) is not loaded by default to keep the page fast.Load diff
added
packages/database/drizzle/0001_lumpy_hulk.sql
+27 −0
Large diff (28 lines) is not loaded by default to keep the page fast.Load diff
added
packages/database/drizzle/meta/0001_snapshot.json
+2801 −0
Large diff (2,802 lines) is not loaded by default to keep the page fast.Load diff
modified
packages/database/drizzle/meta/_journal.json
+7 −0
Large diff (14 lines) is not loaded by default to keep the page fast.Load diff
modified
packages/database/src/schema.ts
+31 −0
Large diff (37 lines) is not loaded by default to keep the page fast.Load diff
modified
packages/database/src/sync-games.ts
+50 −2
Large diff (71 lines) is not loaded by default to keep the page fast.Load diff
modified
packages/game-core/src/client.ts
+2 −0
Large diff (5 lines) is not loaded by default to keep the page fast.Load diff
added
packages/game-core/src/crash/curve.ts
+162 −0
Large diff (162 lines) is not loaded by default to keep the page fast.Load diff
added
packages/game-core/src/crash/index.ts
+228 −0
Large diff (228 lines) is not loaded by default to keep the page fast.Load diff
modified
packages/game-core/src/index.ts
+1 −0
Large diff (5 lines) is not loaded by default to keep the page fast.Load diff