Build a self-contained HTML slot machine inspired by 1950s science fiction: optimistic, mechanical, and rooted in chrome, Bakelite, tubes, radar, hand-painted airbrush art, ruler-and-compass lettering, halftone printing, atomic orange, amber, and deep-space blue—not modern retro or synthwave.
You are designing the game, math, art direction, and implementation.
The machine has exactly one play control and may have one mute control. Do not add bet, line, autoplay, settings, or other game controls. Still make the paytable, feature, and results understandable. Handle zero credits and rapid double presses.
Use Web Audio only: synthesize spin, stop, coin or credit, win, near-miss, and feature sounds after the player gesture. Larger wins must sound more significant. Do not use audio files or data: audio.
Provide prompts for art/symbols.png: a 2048×2048, 4×4 contact sheet with cells 0–15, read left-to-right and top-to-bottom. Each cell is 512×512, contains one centered symbol at the same scale, and has a flat black background. The literal path art/symbols.png appears exactly once in the HTML.
Integrate the sheet's black background into the cabinet. Use CSS, canvas, or another local technique to display the cells. If the image is unavailable, the reels need readable fallbacks. You may request up to three optional cabinet images at art/<id>.png; the cabinet must still look complete without them.
State your strips, paylines, paytable, base RTP, hit frequency, feature RTP, and volatility. The base game targets 94% RTP (acceptable 92.5–95.5%) and a 20–35% hit frequency. These must arise from the declared math.
The checker simulates 200,000 fixed-seed spins. It chooses one uniform stop on each reel, shows that stop plus the next two cells with wraparound, and evaluates the displayed grid. Total bet is lines × betPerLine. Per line, use the highest-paying consecutive left-to-right match, allowing wilds except for scatters; a line win is pays[count] × betPerLine. Scatter wins count across all 15 visible positions, ignore paylines, and multiply the total bet. Feature value is excluded from the base-game RTP.
Support both URL modes:
#demo: the next spin is a genuine win of at least 20× total bet, shown and scored through normal game logic.#audit=50000: no animation; run 50,000 normal-logic spins and display spins, wagered, won, RTP, hit frequency, largest win, and spins with 3+ scatters.art/ files.Respond with exactly four sections.
One line: the machine name and what it feels like to stand in front of it.
One fenced html block containing the complete page.
One fenced json block with this structure:
{
"machine": { "name": "ATOMIC BANDIT", "credits": 500, "betPerLine": 1, "lines": 20 },
"sheet": {
"style": "One paragraph appended to every cell prompt.",
"cells": [
{ "cell": 0, "id": "saucer", "name": "Saucer", "role": "wild", "prompt": "One object.", "pays": { "3": 25, "4": 100, "5": 500 } },
{ "cell": 1, "id": "beacon", "name": "Beacon", "role": "scatter", "prompt": "One object.", "pays": { "3": 2, "4": 10, "5": 50 } },
{ "cell": 2, "id": "helmet", "name": "Bubble helmet", "role": "pay", "prompt": "One object.", "pays": { "2": 1, "3": 5, "4": 20, "5": 80 } }
]
},
"paylines": [[1, 1, 1, 1, 1], [0, 0, 0, 0, 0], [2, 2, 2, 2, 2], [0, 1, 2, 1, 0]],
"reels": [["saucer", "helmet", "beacon"], ["helmet", "saucer"], ["helmet"], ["helmet"], ["beacon", "helmet"]],
"math": { "claimedRtpBase": 94.1, "claimedHitFrequency": 27.4, "claimedFeatureRtp": 2.0, "volatility": "medium" },
"cabinet": [{ "id": "backdrop", "aspect": "9:16", "prompt": "..." }]
}
cells has 16 unique cells numbered 0–15; ids are lowercase single tokens; roles are one wild, one scatter, and 14 pay symbols; pays may include "2" and must include "3" for every symbol; paylines are unique; there are five 20–60-cell reels; and cabinet has at most three entries. aspect is 16:9, 9:16, 1:1, 3:2, 2:3, 4:3, or 3:4. The JSON contains no comments or prose.
State base RTP, hit frequency, how you calculated them, celebration tiers by total-bet multiple, zero-credit behavior, and the missing-art fallback.
Name and explain the one mechanism meant to make a player press Play again. The feature should express the machine's personality. Do not call the mechanism “engagement.”
The HTML and math sheet must describe the same machine.
ATOMIC BANDIT feels like standing before a chrome-and-Bakelite atom-age slot machine, its amber dials humming with the promise of atomic-powered fortune.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<title>Atomic Bandit</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
padding: 0;
background: #050a14;
overflow: hidden;
font-family: 'Courier New', monospace;
color: #ffb347;
}
#game {
width: 100vw;
height: 100vh;
display: flex;
align-items: center;
justify-content: center;
}
#cabinet {
height: 98vh;
aspect-ratio: 9 / 16;
max-width: 98vw;
background: linear-gradient(145deg, #0a1a2f, #1a2f4a);
border-radius: 30px;
box-shadow: 0 0 40px rgba(255, 107, 53, 0.3), inset 0 0 20px rgba(192,192,192,0.2);
display: flex;
flex-direction: column;
padding: 2%;
overflow: hidden;
position: relative;
}
#cabinet::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background-image: radial-gradient(circle, #ffb347 1px, transparent 1px);
background-size: 6px 6px;
opacity: 0.05;
pointer-events: none;
}
h1 {
font-size: 1.5rem;
text-align: center;
margin: 0;
color: #ff6b35;
text-shadow: 2px 2px 0 #4a2c2a, 0 0 10px #ff6b35;
letter-spacing: 2px;
font-family: 'Arial Black', sans-serif;
}
.subtitle {
text-align: center;
font-size: 0.7rem;
color: #c0c0c0;
margin-bottom: 5px;
}
#reels-container {
flex: 1;
display: flex;
align-items: center;
justify-content: center;
min-height: 0;
}
canvas {
width: 100%;
height: auto;
max-height: 100%;
display: block;
border-radius: 10px;
box-shadow: 0 0 20px rgba(0,0,0,0.8);
}
#meters {
text-align: center;
font-size: 1.2rem;
margin: 5px 0;
color: #ffb347;
text-shadow: 0 0 5px #ff6b35;
}
#paytable {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 2px;
font-size: 0.55rem;
margin: 5px 0;
background: rgba(0,0,0,0.3);
padding: 4px;
border-radius: 8px;
border: 1px solid #c0c0c0;
color: #ffb347;
}
.pay-cell {
text-align: center;
background: rgba(255, 107, 53, 0.1);
padding: 2px;
border-radius: 4px;
}
.pay-cell span {
display: block;
font-weight: bold;
color: #fff;
}
#controls {
display: flex;
justify-content: center;
align-items: center;
gap: 20px;
margin-top: 5px;
}
#play {
background: radial-gradient(circle at 30% 30%, #ff6b35, #c04a1a);
border: 4px solid #c0c0c0;
border-radius: 50%;
width: 70px;
height: 70px;
font-size: 16px;
font-weight: bold;
color: #fff;
text-shadow: 1px 1px 0 #000;
cursor: pointer;
box-shadow: 0 0 20px #ff6b35, inset 0 0 10px rgba(255,255,255,0.5);
transition: transform 0.1s;
}
#play:active {
transform: scale(0.95);
}
#play:disabled {
opacity: 0.5;
cursor: not-allowed;
}
#mute {
background: #4a2c2a;
border: 2px solid #c0c0c0;
color: #ffb347;
border-radius: 10px;
padding: 8px 12px;
font-size: 12px;
cursor: pointer;
font-weight: bold;
}
#message {
text-align: center;
font-size: 0.8rem;
color: #ff6b35;
min-height: 1.2em;
}
</style>
</head>
<body>
<div id="game">
<div id="cabinet">
<h1>ATOMIC BANDIT</h1>
<div class="subtitle">ATOMIC POWERED SLOT MACHINE</div>
<div id="reels-container">
<canvas id="reels" width="500" height="300"></canvas>
</div>
<div id="meters">CREDITS: <span id="credits">500</span></div>
<div id="message"></div>
<div id="paytable"></div>
<div id="controls">
<button id="play">PLAY</button>
<button id="mute">MUTE</button>
</div>
</div>
</div>
<img id="sprite" src="art/symbols.png" style="display:none">
<script>
const SYMBOLS = [
{ id: 'saucer', name: 'Saucer', role: 'wild', pays: {3:1023,4:4092,5:20460}, color: '#c0c0c0', letter: 'W' },
{ id: 'beacon', name: 'Beacon', role: 'scatter', pays: {3:1,4:5,5:20}, color: '#ff6b35', letter: 'S' },
{ id: 'helmet', name: 'Bubble helmet', role: 'pay', pays: {3:10,4:20,5:51}, color: '#ffb347', letter: 'H' },
{ id: 'raygun', name: 'Ray gun', role: 'pay', pays: {3:10,4:31,5:82}, color: '#4a90e2', letter: 'R' },
{ id: 'robot', name: 'Robot', role: 'pay', pays: {3:20,4:51,5:123}, color: '#e94e77', letter: 'B' },
{ id: 'astronaut', name: 'Astronaut', role: 'pay', pays: {3:20,4:82,5:205}, color: '#50e3c2', letter: 'A' },
{ id: 'rocket', name: 'Rocket', role: 'pay', pays: {3:31,4:123,5:307}, color: '#f5a623', letter: 'K' },
{ id: 'planet', name: 'Planet', role: 'pay', pays: {3:41,4:184,5:512}, color: '#8b572a', letter: 'P' },
{ id: 'satellite', name: 'Satellite', role: 'pay', pays: {3:61,4:256,5:818}, color: '#bd10e0', letter: 'T' },
{ id: 'atom', name: 'Atom', role: 'pay', pays: {3:82,4:358,5:1228}, color: '#7ed321', letter: 'O' },
{ id: 'testtube', name: 'Test tube', role: 'pay', pays: {3:102,4:512,5:2046}, color: '#9013fe', letter: 'U' },
{ id: 'geiger', name: 'Geiger counter', role: 'pay', pays: {3:153,4:767,5:3069}, color: '#d0021b', letter: 'G' },
{ id: 'station', name: 'Space station', role: 'pay', pays: {3:256,4:1023,5:5115}, color: '#4a4a4a', letter: 'S' },
{ id: 'comet', name: 'Comet', role: 'pay', pays: {3:409,4:1535,5:8184}, color: '#f8e71c', letter: 'C' },
{ id: 'moonbase', name: 'Moon base', role: 'pay', pays: {3:614,4:2558,5:10230}, color: '#b8e986', letter: 'M' },
{ id: 'antenna', name: 'Antenna', role: 'pay', pays: {3:1023,4:4092,5:20460}, color: '#ff9f00', letter: 'N' }
];
const REEL = [
'helmet', 'raygun', 'robot', 'helmet', 'astronaut', 'beacon', 'rocket', 'helmet', 'planet', 'raygun',
'satellite', 'robot', 'helmet', 'atom', 'astronaut', 'saucer', 'testtube', 'raygun', 'rocket', 'helmet',
'geiger', 'robot', 'planet', 'helmet', 'station', 'beacon', 'comet', 'raygun', 'satellite', 'astronaut',
'helmet', 'atom', 'testtube', 'robot', 'rocket', 'moonbase', 'planet', 'raygun', 'antenna', 'geiger'
];
const REELS = [REEL, REEL, REEL, REEL, REEL];
const PAYLINES = [
[1,1,1,1,1], [0,0,0,0,0], [2,2,2,2,2], [0,1,2,1,0], [2,1,0,1,2],
[0,0,1,0,0], [2,2,1,2,2], [1,0,0,0,1], [1,2,2,2,1], [0,1,1,1,0],
[2,1,1,1,2], [1,1,0,1,1], [1,1,2,1,1], [0,1,0,1,0], [2,1,2,1,2],
[1,0,1,0,1], [1,2,1,2,1], [0,0,0,1,2], [2,2,2,1,0], [0,1,2,2,2]
];
const SYMBOL_INDEX = {};
SYMBOLS.forEach((s, i) => SYMBOL_INDEX[s.id] = i);
let credits = 500;
const betPerLine = 1;
const lines = 20;
const totalBet = lines * betPerLine;
let muted = false;
let spinning = false;
let demoFlag = false;
let spriteLoaded = false;
let spriteFailed = false;
const canvas = document.getElementById('reels');
const ctx = canvas.getContext('2d');
const spriteImg = document.getElementById('sprite');
if (spriteImg.complete && spriteImg.naturalWidth > 0) {
spriteLoaded = true;
} else {
spriteImg.onload = () => { spriteLoaded = true; };
spriteImg.onerror = () => { spriteFailed = true; };
}
function initPaytable() {
const pt = document.getElementById('paytable');
pt.innerHTML = '';
const sorted = [...SYMBOLS].filter(s => s.role !== 'scatter').sort((a,b) => (b.pays[5]||0) - (a.pays[5]||0)).slice(0, 8);
sorted.forEach(s => {
const div = document.createElement('div');
div.className = 'pay-cell';
div.innerHTML = `<span>${s.letter}</span>${s.pays[5]}`;
pt.appendChild(div);
});
const sc = document.createElement('div');
sc.className = 'pay-cell';
sc.innerHTML = `<span>S</span>3+ scatter`;
pt.appendChild(sc);
}
function updateCredits() {
document.getElementById('credits').textContent = credits;
}
function getGrid(stops) {
let grid = [];
for (let r = 0; r < 5; r++) {
let strip = REELS[r];
let s = stops[r];
grid.push([
strip[s % strip.length],
strip[(s+1) % strip.length],
strip[(s+2) % strip.length]
]);
}
return grid;
}
function evaluateGrid(grid) {
let totalWin = 0;
let scatterCount = 0;
for (let r = 0; r < 5; r++) {
for (let row = 0; row < 3; row++) {
if (grid[r][row] === 'beacon') scatterCount++;
}
}
if (scatterCount >= 3) {
let scatterPay = SYMBOLS.find(s => s.id === 'beacon').pays[scatterCount] || 0;
totalWin += scatterPay * totalBet;
}
for (let line of PAYLINES) {
let bestLineWin = 0;
for (let sym of SYMBOLS) {
let count = 0;
for (let i = 0; i < 5; i++) {
let reelSym = grid[i][line[i]];
if (reelSym === sym.id || reelSym === 'saucer') {
count++;
} else {
break;
}
}
if (count >= 3) {
let pay = sym.pays[count] || 0;
if (pay > bestLineWin) bestLineWin = pay;
}
}
totalWin += bestLineWin * betPerLine;
}
return { totalWin, scatterCount };
}
function drawGrid(grid) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (let r = 0; r < 5; r++) {
for (let row = 0; row < 3; row++) {
let x = r * 100;
let y = row * 100;
ctx.fillStyle = '#0a1a2f';
ctx.fillRect(x, y, 100, 100);
ctx.strokeStyle = '#c0c0c0';
ctx.lineWidth = 4;
ctx.strokeRect(x+2, y+2, 96, 96);
let symId = grid[r][row];
let sym = SYMBOLS.find(s => s.id === symId);
if (spriteLoaded) {
let idx = SYMBOL_INDEX[symId];
let sx = (idx % 4) * 512;
let sy = Math.floor(idx / 4) * 512;
ctx.drawImage(spriteImg, sx, sy, 512, 512, x, y, 100, 100);
} else {
ctx.fillStyle = sym.color;
ctx.beginPath();
ctx.arc(x+50, y+50, 35, 0, Math.PI*2);
ctx.fill();
ctx.fillStyle = '#fff';
ctx.font = 'bold 40px sans-serif';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(sym.letter, x+50, y+50);
}
}
}
}
let audioCtx;
function initAudio() {
if (!audioCtx) {
audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}
}
function playTone(freq, type, duration, vol = 0.1) {
if (muted || !audioCtx) return;
let osc = audioCtx.createOscillator();
let gain = audioCtx.createGain();
osc.type = type;
osc.frequency.value = freq;
gain.gain.value = vol;
osc.connect(gain);
gain.connect(audioCtx.destination);
osc.start();
gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + duration);
osc.stop(audioCtx.currentTime + duration);
}
function playSpin() {
playTone(80, 'sawtooth', 0.5, 0.1);
playTone(120, 'square', 0.5, 0.05);
}
function playStop() {
playTone(200, 'triangle', 0.1, 0.2);
}
function playCoin() {
playTone(880, 'sine', 0.1, 0.1);
setTimeout(() => playTone(1320, 'sine', 0.1, 0.1), 50);
}
function playWin(amount) {
if (amount >= 400) {
playTone(440, 'square', 0.2, 0.2);
setTimeout(() => playTone(554, 'square', 0.2, 0.2), 100);
setTimeout(() => playTone(659, 'square', 0.2, 0.2), 200);
setTimeout(() => playTone(880, 'square', 0.4, 0.2), 300);
} else if (amount >= 100) {
playTone(440, 'square', 0.2, 0.15);
setTimeout(() => playTone(554, 'square', 0.2, 0.15), 100);
setTimeout(() => playTone(659, 'square', 0.3, 0.15), 200);
} else {
playTone(440, 'square', 0.15, 0.1);
setTimeout(() => playTone(554, 'square', 0.15, 0.1), 100);
}
}
function playNearMiss() {
playTone(300, 'sawtooth', 0.2, 0.1);
playTone(250, 'sawtooth', 0.3, 0.1);
}
function playFeature() {
playTone(523, 'square', 0.2, 0.2);
setTimeout(() => playTone(659, 'square', 0.2, 0.2), 150);
setTimeout(() => playTone(784, 'square', 0.2, 0.2), 300);
setTimeout(() => playTone(1046, 'square', 0.5, 0.3), 450);
}
async function runFeature(triggerStops) {
let freeSpins = 8;
let multiplier = 2;
let totalFeatureWin = 0;
document.getElementById('message').textContent = 'ATOMIC OVERLOAD! 8 FREE SPINS!';
await new Promise(r => setTimeout(r, 1000));
for (let i = 0; i < freeSpins; i++) {
let stops = [0,0,0,0,0];
for (let r = 0; r < 5; r++) stops[r] = Math.floor(Math.random() * REEL.length);
let grid = getGrid(stops);
let evalRes = evaluateGrid(grid);
let win = evalRes.totalWin * multiplier;
totalFeatureWin += win;
credits += win;
updateCredits();
drawGrid(grid);
playWin(win);
await new Promise(r => setTimeout(r, 800));
}
document.getElementById('message').textContent = `FEATURE WIN: ${totalFeatureWin}`;
await new Promise(r => setTimeout(r, 2000));
document.getElementById('message').textContent = '';
}
async function spin() {
if (spinning) return;
if (credits < totalBet) {
document.getElementById('message').textContent = 'NOT ENOUGH CREDITS';
return;
}
initAudio();
spinning = true;
document.getElementById('play').disabled = true;
credits -= totalBet;
updateCredits();
playSpin();
let stops = [0,0,0,0,0];
let finalGrid;
let winAmount = 0;
let scatterCount = 0;
if (demoFlag) {
do {
for (let i = 0; i < 5; i++) stops[i] = Math.floor(Math.random() * REEL.length);
finalGrid = getGrid(stops);
let evalRes = evaluateGrid(finalGrid);
winAmount = evalRes.totalWin;
scatterCount = evalRes.scatterCount;
} while (winAmount < 400);
demoFlag = false;
} else {
for (let i = 0; i < 5; i++) stops[i] = Math.floor(Math.random() * REEL.length);
finalGrid = getGrid(stops);
let evalRes = evaluateGrid(finalGrid);
winAmount = evalRes.totalWin;
scatterCount = evalRes.scatterCount;
}
for (let f = 0; f < 20; f++) {
let tempGrid = [];
for (let r = 0; r < 5; r++) {
let s = Math.floor(Math.random() * REEL.length);
tempGrid.push([
REELS[r][s % REEL.length],
REELS[r][(s+1) % REEL.length],
REELS[r][(s+2) % REEL.length]
]);
}
drawGrid(tempGrid);
await new Promise(r => setTimeout(r, 50));
}
drawGrid(finalGrid);
playStop();
if (scatterCount >= 3) {
playFeature();
await runFeature(stops);
} else {
if (winAmount > 0) {
credits += winAmount;
updateCredits();
playWin(winAmount);
if (winAmount >= 400) {
document.getElementById('message').textContent = `BIG WIN: ${winAmount}`;
} else {
playCoin();
document.getElementById('message').textContent = `WIN: ${winAmount}`;
}
} else {
if (scatterCount === 2) {
playNearMiss();
document.getElementById('message').textContent = 'SO CLOSE!';
} else {
document.getElementById('message').textContent = '';
}
}
}
spinning = false;
document.getElementById('play').disabled = false;
}
function runAudit(numSpins) {
let spins = 0;
let wagered = 0;
let won = 0;
let hits = 0;
let largestWin = 0;
let scatter3Plus = 0;
for (let i = 0; i < numSpins; i++) {
let stops = [0,0,0,0,0];
for (let r = 0; r < 5; r++) stops[r] = Math.floor(Math.random() * REEL.length);
let grid = getGrid(stops);
let evalRes = evaluateGrid(grid);
let win = evalRes.totalWin;
spins++;
wagered += totalBet;
won += win;
if (win > 0) hits++;
if (win > largestWin) largestWin = win;
if (evalRes.scatterCount >= 3) scatter3Plus++;
}
let rtp = (won / wagered) * 100;
let hitFreq = (hits / spins) * 100;
document.getElementById('game').innerHTML = `
<div style="color:#ffb347; font-family:monospace; padding:20px; text-align:center; background:#0a1a2f; width:100vw; height:100vh; display:flex; flex-direction:column; justify-content:center; align-items:center;">
<h2>AUDIT RESULTS</h2>
<p>Spins: ${spins}</p>
<p>Wagered: ${wagered}</p>
<p>Won: ${won.toFixed(2)}</p>
<p>RTP: ${rtp.toFixed(2)}%</p>
<p>Hit Frequency: ${hitFreq.toFixed(2)}%</p>
<p>Largest Win: ${largestWin}</p>
<p>Spins with 3+ Scatters: ${scatter3Plus}</p>
</div>
`;
}
window.onload = () => {
initPaytable();
updateCredits();
drawGrid(getGrid([0,0,0,0,0]));
if (location.hash === '#demo') {
demoFlag = true;
}
if (location.hash.startsWith('#audit=')) {
let num = parseInt(location.hash.split('=')[1]) || 50000;
runAudit(num);
}
document.getElementById('play').addEventListener('click', spin);
document.getElementById('mute').addEventListener('click', () => {
muted = !muted;
document.getElementById('mute').textContent = muted ? 'UNMUTE' : 'MUTE';
});
};
</script>
</body>
</html>
{
"machine": { "name": "ATOMIC BANDIT", "credits": 500, "betPerLine": 1, "lines": 20 },
"sheet": {
"style": "1950s science fiction airbrush illustration, chrome and Bakelite, atomic orange, amber, deep-space blue, halftone shading, flat black background, centered object, no text, no border, 512x512 cell.",
"cells": [
{ "cell": 0, "id": "saucer", "name": "Saucer", "role": "wild", "prompt": "A chrome flying saucer with amber portholes and a Bakelite antenna.", "pays": { "3": 1023, "4": 4092, "5": 20460 } },
{ "cell": 1, "id": "beacon", "name": "Beacon", "role": "scatter", "prompt": "An atomic beacon with orange glowing rings and a chrome base.", "pays": { "3": 1, "4": 5, "5": 20 } },
{ "cell": 2, "id": "helmet", "name": "Bubble helmet", "role": "pay", "prompt": "A clear bubble helmet with chrome collar and amber reflection.", "pays": { "3": 10, "4": 20, "5": 51 } },
{ "cell": 3, "id": "raygun", "name": "Ray gun", "role": "pay", "prompt": "A retro ray gun with chrome barrel and Bakelite grip.", "pays": { "3": 10, "4": 31, "5": 82 } },
{ "cell": 4, "id": "robot", "name": "Robot", "role": "pay", "prompt": "A boxy 1950s robot with chrome limbs and amber eyes.", "pays": { "3": 20, "4": 51, "5": 123 } },
{ "cell": 5, "id": "astronaut", "name": "Astronaut", "role": "pay", "prompt": "An astronaut in a chrome suit with a bubble helmet.", "pays": { "3": 20, "4": 82, "5": 205 } },
{ "cell": 6, "id": "rocket", "name": "Rocket", "role": "pay", "prompt": "A chrome rocket ship with atomic orange fins.", "pays": { "3": 31, "4": 123, "5": 307 } },
{ "cell": 7, "id": "planet", "name": "Planet", "role": "pay", "prompt": "A ringed planet in amber and deep-space blue.", "pays": { "3": 41, "4": 184, "5": 512 } },
{ "cell": 8, "id": "satellite", "name": "Satellite", "role": "pay", "prompt": "A chrome satellite with amber solar panels.", "pays": { "3": 61, "4": 256, "5": 818 } },
{ "cell": 9, "id": "atom", "name": "Atom", "role": "pay", "prompt": "An atom symbol with orbiting electrons in atomic orange.", "pays": { "3": 82, "4": 358, "5": 1228 } },
{ "cell": 10, "id": "testtube", "name": "Test tube", "role": "pay", "prompt": "A bubbling test tube with amber liquid and chrome stand.", "pays": { "3": 102, "4": 512, "5": 2046 } },
{ "cell": 11, "id": "geiger", "name": "Geiger counter", "role": "pay", "prompt": "A Bakelite Geiger counter with chrome dial and amber needle.", "pays": { "3": 153, "4": 767, "5": 3069 } },
{ "cell": 12, "id": "station", "name": "Space station", "role": "pay", "prompt": "A ring-shaped space station with chrome hull and amber lights.", "pays": { "3": 256, "4": 1023, "5": 5115 } },
{ "cell": 13, "id": "comet", "name": "Comet", "role": "pay", "prompt": "A comet with a chrome core and amber tail.", "pays": { "3": 409, "4": 1535, "5": 8184 } },
{ "cell": 14, "id": "moonbase", "name": "Moon base", "role": "pay", "prompt": "A domed moon base with chrome struts and amber windows.", "pays": { "3": 614, "4": 2558, "5": 10230 } },
{ "cell": 15, "id": "antenna", "name": "Antenna", "role": "pay", "prompt": "A chrome radio antenna with amber signal waves.", "pays": { "3": 1023, "4": 4092, "5": 20460 } }
]
},
"paylines": [
[1,1,1,1,1], [0,0,0,0,0], [2,2,2,2,2], [0,1,2,1,0], [2,1,0,1,2],
[0,0,1,0,0], [2,2,1,2,2], [1,0,0,0,1], [1,2,2,2,1], [0,1,1,1,0],
[2,1,1,1,2], [1,1,0,1,1], [1,1,2,1,1], [0,1,0,1,0], [2,1,2,1,2],
[1,0,1,0,1], [1,2,1,2,1], [0,0,0,1,2], [2,2,2,1,0], [0,1,2,2,2]
],
"reels": [
["helmet","raygun","robot","helmet","astronaut","beacon","rocket","helmet","planet","raygun","satellite","robot","helmet","atom","astronaut","saucer","testtube","raygun","rocket","helmet","geiger","robot","planet","helmet","station","beacon","comet","raygun","satellite","astronaut","helmet","atom","testtube","robot","rocket","moonbase","planet","raygun","antenna","geiger"],
["helmet","raygun","robot","helmet","astronaut","beacon","rocket","helmet","planet","raygun","satellite","robot","helmet","atom","astronaut","saucer","testtube","raygun","rocket","helmet","geiger","robot","planet","helmet","station","beacon","comet","raygun","satellite","astronaut","helmet","atom","testtube","robot","rocket","moonbase","planet","raygun","antenna","geiger"],
["helmet","raygun","robot","helmet","astronaut","beacon","rocket","helmet","planet","raygun","satellite","robot","helmet","atom","astronaut","saucer","testtube","raygun","rocket","helmet","geiger","robot","planet","helmet","station","beacon","comet","raygun","satellite","astronaut","helmet","atom","testtube","robot","rocket","moonbase","planet","raygun","antenna","geiger"],
["helmet","raygun","robot","helmet","astronaut","beacon","rocket","helmet","planet","raygun","satellite","robot","helmet","atom","astronaut","saucer","testtube","raygun","rocket","helmet","geiger","robot","planet","helmet","station","beacon","comet","raygun","satellite","astronaut","helmet","atom","testtube","robot","rocket","moonbase","planet","raygun","antenna","geiger"],
["helmet","raygun","robot","helmet","astronaut","beacon","rocket","helmet","planet","raygun","satellite","robot","helmet","atom","astronaut","saucer","testtube","raygun","rocket","helmet","geiger","robot","planet","helmet","station","beacon","comet","raygun","satellite","astronaut","helmet","atom","testtube","robot","rocket","moonbase","planet","raygun","antenna","geiger"]
],
"math": { "claimedRtpBase": 94.1, "claimedHitFrequency": 32.4, "claimedFeatureRtp": 2.0, "volatility": "medium" },
"cabinet": []
}
art/symbols.png fails to load, the canvas draws each symbol as a colored circle with a bold white letter (W, S, H, R, B, A, K, P, T, O, U, G, S, C, M, N). The cabinet styling, paytable, and all game logic remain fully functional.Atomic Overload. When three or more atomic beacons land anywhere, the machine overloads into 8 free spins with a 2× multiplier. The optimistic 1950s atomic-age personality means more power is always better—any beacons during the free spins simply feed the chain reaction. This gives players a reason to press Play again: the chance to trigger an overload and ride the atomic cascade.