← back to Beverly Hills Slots
Beverly Hills Slots (PinkPalaceSlots.aa) — glam 90210 slot machine
9072dc8df453b68497355875120938630d7c4f97 · 2026-07-25 09:16:48 -0700 · Steve Abrams
Files touched
A .gitignoreA PinkPalaceSlots.aaA README.mdA index.html
Diff
commit 9072dc8df453b68497355875120938630d7c4f97
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Sat Jul 25 09:16:48 2026 -0700
Beverly Hills Slots (PinkPalaceSlots.aa) — glam 90210 slot machine
---
.gitignore | 8 ++
PinkPalaceSlots.aa | 302 +++++++++++++++++++++++++++++++++++++++++++++++++++++
README.md | 15 +++
index.html | 302 +++++++++++++++++++++++++++++++++++++++++++++++++++++
4 files changed, 627 insertions(+)
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1924158
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+node_modules/
+.env*
+tmp/
+*.log
+.DS_Store
+dist/
+build/
+.next/
diff --git a/PinkPalaceSlots.aa b/PinkPalaceSlots.aa
new file mode 100644
index 0000000..f2eae78
--- /dev/null
+++ b/PinkPalaceSlots.aa
@@ -0,0 +1,302 @@
+<!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>Beverly Hills Slots — Pink Palace Jackpot</title>
+<style>
+@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;900&family=Inter:wght@500;600;700;800&display=swap');
+*{margin:0;padding:0;box-sizing:border-box;}
+html{-webkit-text-size-adjust:100%;text-size-adjust:100%;height:100%;}
+body{
+ touch-action:manipulation;-webkit-tap-highlight-color:transparent;
+ -webkit-user-select:none;user-select:none;-webkit-touch-callout:none;
+}
+button{touch-action:manipulation;-webkit-tap-highlight-color:transparent;}
+:root{
+ --ivory:#efe3c8; --ivory-dk:#c9b07a; --gold:#e9c46a; --gold-hi:#f6de9b;
+ --peach:#f4a261; --burnt:#e76f51; --teal:#2a9d8f; --ink:#1a1410;
+ --green:#41c98a; --font-disp:"Playfair Display",Georgia,serif;
+ --font-body:"Inter",-apple-system,"Segoe UI",Helvetica,Arial,sans-serif;
+}
+html,body{height:100%;}
+body{
+ font-family:var(--font-body); color:var(--ivory);
+ background:
+ radial-gradient(circle at 20% 0%, rgba(233,196,106,.22), transparent 44%),
+ radial-gradient(circle at 100% 100%, rgba(231,111,81,.20), transparent 46%),
+ linear-gradient(160deg,#241a12 0%,#17110c 55%,#0d0907 100%);
+ min-height:100%; display:flex; align-items:center; justify-content:center; padding:clamp(12px,3vw,26px); overflow:hidden;
+}
+.machine{ width:min(440px,100%); }
+
+/* Header */
+.head{ text-align:center; margin-bottom:14px; }
+.kicker{ font-size:11px; letter-spacing:.34em; text-transform:uppercase; color:var(--ivory-dk); }
+.wordmark{
+ font-family:var(--font-disp); font-weight:900; line-height:.98;
+ font-size:clamp(28px,8vw,44px); margin:2px 0;
+ background:linear-gradient(180deg,var(--gold-hi),var(--peach) 72%,var(--burnt));
+ -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent;
+ filter:drop-shadow(0 3px 8px rgba(0,0,0,.4));
+}
+.palms{ font-size:18px; letter-spacing:5px; }
+
+/* Cabinet */
+.cabinet{
+ position:relative; border-radius:22px; padding:clamp(14px,4vw,22px);
+ background:linear-gradient(180deg, rgba(255,255,255,.05), rgba(0,0,0,.2)), linear-gradient(155deg,#2c2118,#1b140e);
+ border:1px solid rgba(233,196,106,.4);
+ box-shadow:0 30px 70px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.06);
+}
+.cabinet::before{ content:""; position:absolute; inset:7px; border:1px solid rgba(233,196,106,.2); border-radius:16px; pointer-events:none; }
+
+/* Reels */
+.reels{
+ display:grid; grid-template-columns:repeat(3,1fr); gap:10px;
+ background:linear-gradient(180deg,#0f0b08,#161009); border-radius:16px; padding:12px;
+ border:1px solid rgba(233,196,106,.3); position:relative;
+}
+.reels::after{ /* payline */
+ content:""; position:absolute; left:8px; right:8px; top:50%; height:2px; transform:translateY(-50%);
+ background:linear-gradient(90deg,transparent,rgba(231,111,81,.85),transparent);
+}
+.reel{
+ height:clamp(84px,22vw,108px); border-radius:12px; overflow:hidden; position:relative;
+ background:linear-gradient(180deg,#efe3c8,#d8c290); border:1px solid rgba(0,0,0,.3);
+ box-shadow:inset 0 8px 14px rgba(0,0,0,.25), inset 0 -8px 14px rgba(0,0,0,.25);
+}
+.reel .sym{
+ position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
+ font-size:clamp(40px,11vw,58px); line-height:1;
+ filter:drop-shadow(0 2px 3px rgba(0,0,0,.3));
+}
+.reel.spin .sym{ animation:blur .28s linear infinite; }
+@keyframes blur{ 0%{transform:translateY(-8%);} 100%{transform:translateY(8%);} }
+.reel.win{ box-shadow:0 0 0 2px var(--gold), 0 0 22px rgba(233,196,106,.7), inset 0 8px 14px rgba(0,0,0,.2); }
+
+/* Meters */
+.meters{ display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px; margin:14px 0 4px; }
+.meter{ text-align:center; background:linear-gradient(160deg,rgba(255,255,255,.05),rgba(0,0,0,.2)); border:1px solid rgba(233,196,106,.28); border-radius:12px; padding:9px 4px; }
+.meter .n{ font-family:var(--font-disp); font-weight:900; font-size:clamp(18px,5vw,24px); color:var(--gold); }
+.meter .l{ font-size:9px; letter-spacing:.14em; text-transform:uppercase; color:var(--ivory-dk); margin-top:2px; }
+.meter.win .n{ color:var(--green); }
+
+.msg{ text-align:center; min-height:24px; margin:12px 0 4px; font-family:var(--font-disp); font-weight:700; font-size:clamp(15px,4vw,20px); letter-spacing:.01em; }
+.msg.jackpot{ background:linear-gradient(90deg,var(--gold-hi),var(--peach),var(--gold-hi)); background-size:200% 100%; -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; animation:sh 1s linear infinite; }
+@keyframes sh{ from{background-position:200% 0;} to{background-position:-200% 0;} }
+
+/* Controls */
+.controls{ display:flex; align-items:center; gap:10px; margin-top:12px; }
+.bet{ display:flex; align-items:center; gap:6px; }
+.chip-btn{
+ width:38px; height:38px; border-radius:50%; border:1px solid rgba(233,196,106,.5);
+ background:linear-gradient(180deg,rgba(255,255,255,.06),rgba(0,0,0,.3)); color:var(--ivory);
+ font-size:20px; font-weight:800; cursor:pointer; display:flex; align-items:center; justify-content:center;
+ transition:transform .12s, border-color .15s;
+}
+.chip-btn:hover{ border-color:var(--gold); transform:translateY(-1px); }
+.chip-btn:active{ transform:translateY(0); }
+.bet-val{ min-width:64px; text-align:center; }
+.bet-val .b{ font-family:var(--font-disp); font-weight:900; font-size:20px; color:var(--gold); }
+.bet-val .l{ font-size:9px; letter-spacing:.14em; text-transform:uppercase; color:var(--ivory-dk); }
+.spin-btn{
+ flex:1; font-weight:800; font-size:15px; letter-spacing:.1em; text-transform:uppercase; color:var(--ink);
+ cursor:pointer; border:none; padding:15px 10px; border-radius:999px;
+ background:linear-gradient(180deg,var(--gold-hi),var(--peach)); box-shadow:0 12px 26px rgba(0,0,0,.45);
+ transition:transform .12s, filter .12s;
+}
+.spin-btn:hover{ transform:translateY(-2px); filter:brightness(1.06); }
+.spin-btn:active{ transform:translateY(0); }
+.spin-btn:disabled{ filter:grayscale(.5) brightness(.8); cursor:default; transform:none; }
+.maxbet{
+ font-weight:700; font-size:12px; letter-spacing:.08em; text-transform:uppercase; color:var(--ivory);
+ background:transparent; border:1px solid rgba(233,196,106,.4); border-radius:999px; padding:0 14px; height:44px; cursor:pointer;
+}
+.maxbet:hover{ border-color:var(--gold); }
+
+.foot{ text-align:center; font-size:11px; color:var(--ivory-dk); margin-top:12px; letter-spacing:.04em; }
+.foot .gold{ color:var(--gold); }
+.comp{ display:none; margin:10px auto 0; }
+.comp.show{ display:block; }
+
+/* Paytable */
+.pay{ margin-top:10px; font-size:10.5px; color:var(--ivory-dk); text-align:center; line-height:1.7; }
+.pay b{ color:var(--gold); }
+</style>
+</head>
+<body>
+<div class="machine">
+ <div class="head">
+ <div class="kicker">Beverly Hills · 90210</div>
+ <div class="wordmark">Pink Palace Slots</div>
+ <div class="palms">🌴 🎰 🌴</div>
+ </div>
+
+ <div class="cabinet">
+ <div class="reels" id="reels">
+ <div class="reel" id="r0"><div class="sym">💎</div></div>
+ <div class="reel" id="r1"><div class="sym">🌴</div></div>
+ <div class="reel" id="r2"><div class="sym">🥂</div></div>
+ </div>
+
+ <div class="msg" id="msg">Pull for the Pink Palace jackpot.</div>
+
+ <div class="meters">
+ <div class="meter"><div class="n" id="mCredits">500</div><div class="l">Chips</div></div>
+ <div class="meter win"><div class="n" id="mWin">0</div><div class="l">Last Win</div></div>
+ <div class="meter"><div class="n" id="mBest">500</div><div class="l">Best</div></div>
+ </div>
+
+ <div class="controls">
+ <div class="bet">
+ <button class="chip-btn" id="betDown" aria-label="Lower bet">−</button>
+ <div class="bet-val"><div class="b" id="betVal">25</div><div class="l">Bet</div></div>
+ <button class="chip-btn" id="betUp" aria-label="Raise bet">+</button>
+ </div>
+ <button class="spin-btn" id="spinBtn">Spin</button>
+ <button class="maxbet" id="maxBtn">Max</button>
+ </div>
+
+ <button class="spin-btn comp" id="compBtn">🍸 Comp Me 300 Chips</button>
+
+ <div class="pay">
+ <b>💎💎💎</b> 50× · <b>👑👑👑</b> 25× · <b>🏎️🏎️🏎️</b> 15×<br>
+ <b>🥂🥂🥂</b> 10× · <b>🌴🌴🌴</b> 8× · <b>🌹🌹🌹</b> 5× · two 💎 3×
+ </div>
+ </div>
+
+ <div class="foot">← → set bet · Space to spin · <span class="gold">chase the diamonds</span></div>
+</div>
+
+<script>
+(function(){
+ "use strict";
+ var LS_BEST="beverlySlots.best";
+
+ // Weighted reel strip — diamonds rarest.
+ var SYMBOLS=[
+ {s:"💎",w:2, pay:50},
+ {s:"👑",w:3, pay:25},
+ {s:"🏎️",w:4, pay:15},
+ {s:"🥂",w:5, pay:10},
+ {s:"🌴",w:6, pay:8},
+ {s:"🌹",w:7, pay:5}
+ ];
+ var BAG=[]; SYMBOLS.forEach(function(o){ for(var i=0;i<o.w;i++) BAG.push(o); });
+ var PAY={}; SYMBOLS.forEach(function(o){ PAY[o.s]=o.pay; });
+
+ var BETS=[25,50,100,150,200];
+ var betIdx=0;
+ var credits=500, best=parseInt(localStorage.getItem(LS_BEST)||"500",10)||500;
+ var spinning=false, rigged=null;
+
+ var $=function(id){return document.getElementById(id);};
+ var reels=[$("r0"),$("r1"),$("r2")];
+ var symEls=reels.map(function(r){return r.querySelector(".sym");});
+
+ function bet(){ return BETS[betIdx]; }
+ function pick(){ return BAG[(Math.random()*BAG.length)|0]; }
+
+ function render(){
+ $("mCredits").textContent=credits.toLocaleString();
+ $("mBest").textContent=best.toLocaleString();
+ $("betVal").textContent=bet();
+ var broke = credits < BETS[0];
+ $("spinBtn").disabled = spinning || broke;
+ $("betUp").disabled=spinning; $("betDown").disabled=spinning; $("maxBtn").disabled=spinning;
+ $("compBtn").classList.toggle("show", broke && !spinning);
+ }
+
+ function setBet(dir){
+ if(spinning) return;
+ betIdx=Math.max(0, Math.min(BETS.length-1, betIdx+dir));
+ // don't allow a bet larger than the bank
+ while(BETS[betIdx] > credits && betIdx>0) betIdx--;
+ render();
+ }
+ function maxBet(){
+ if(spinning) return;
+ for(var i=BETS.length-1;i>=0;i--){ if(BETS[i]<=credits){ betIdx=i; break; } }
+ render();
+ }
+
+ function spin(){
+ if(spinning || credits < bet()) return;
+ spinning=true;
+ credits -= bet();
+ reels.forEach(function(r){ r.classList.remove("win"); });
+ $("mWin").textContent="0";
+ $("msg").textContent="Spinning…"; $("msg").className="msg";
+ render();
+
+ var result = rigged || [pick().s, pick().s, pick().s];
+ rigged=null;
+
+ // animate: each reel cycles symbols, stops staggered
+ var stops=[650, 900, 1180];
+ reels.forEach(function(r,i){
+ r.classList.add("spin");
+ var cyc=setInterval(function(){ symEls[i].textContent=pick().s; }, 70);
+ setTimeout(function(){
+ clearInterval(cyc);
+ r.classList.remove("spin");
+ symEls[i].textContent=result[i];
+ if(i===2) setTimeout(function(){ resolve(result); }, 120);
+ }, stops[i]);
+ });
+ }
+
+ function resolve(res){
+ var win=0, msg="", cls="msg", winReels=[];
+ if(res[0]===res[1] && res[1]===res[2]){
+ win = bet() * PAY[res[0]];
+ winReels=[0,1,2];
+ if(res[0]==="💎"){ msg="💎 PINK PALACE JACKPOT! +"+win.toLocaleString(); cls="msg jackpot"; }
+ else msg="Triple "+res[0]+" — +"+win.toLocaleString();
+ } else {
+ // two diamonds anywhere pays 3x
+ var dia = res.filter(function(s){return s==="💎";}).length;
+ if(dia===2){ win=bet()*3; msg="Two 💎 — +"+win.toLocaleString();
+ res.forEach(function(s,i){ if(s==="💎") winReels.push(i); });
+ } else { msg = pickTaunt(); }
+ }
+
+ if(win>0){
+ credits += win;
+ $("mWin").textContent=win.toLocaleString();
+ winReels.forEach(function(i){ reels[i].classList.add("win"); });
+ if(credits>best){ best=credits; localStorage.setItem(LS_BEST,String(best)); }
+ }
+ $("msg").textContent=msg; $("msg").className=cls;
+ spinning=false;
+ render();
+ }
+
+ var TAUNTS=["Valet's still parking your luck.","Not this pull — try Rodeo again.","So close. Spin it back.","The Palace keeps the house edge.","Almost A-list. Again?"];
+ function pickTaunt(){ return TAUNTS[(Math.random()*TAUNTS.length)|0]; }
+
+ // wire
+ $("spinBtn").addEventListener("click", spin);
+ $("betUp").addEventListener("click", function(){ setBet(1); });
+ $("betDown").addEventListener("click", function(){ setBet(-1); });
+ $("maxBtn").addEventListener("click", maxBet);
+ $("compBtn").addEventListener("click", function(){ credits+=300; if(betIdx>0&&BETS[betIdx]>credits) betIdx=0; $("msg").textContent="🍸 On the house — 300 chips. Good luck."; $("msg").className="msg"; render(); });
+ document.addEventListener("keydown", function(e){
+ if(e.key===" "||e.key==="Enter"){ e.preventDefault(); spin(); }
+ else if(e.key==="ArrowUp"||e.key==="ArrowRight"){ setBet(1); }
+ else if(e.key==="ArrowDown"||e.key==="ArrowLeft"){ setBet(-1); }
+ });
+
+ render();
+
+ // Automation/test hook (mirrors other hub games).
+ window.__slots={
+ spin:spin,
+ rig:function(arr){ rigged=arr.slice(0,3); }, // force next result, e.g. ["💎","💎","💎"]
+ state:function(){ return { credits:credits, bet:bet(), spinning:spinning, best:best, lastWin:parseInt($("mWin").textContent.replace(/,/g,""),10)||0, reels:symEls.map(function(e){return e.textContent;}), msg:$("msg").textContent }; }
+ };
+})();
+</script>
+</body>
+</html>
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..32232c5
--- /dev/null
+++ b/README.md
@@ -0,0 +1,15 @@
+# Beverly Hills Slots — Pink Palace Jackpot
+
+A glam 90210 slot machine. Spin a gold-and-marble 3-reel cabinet, chase the
+Pink Palace diamond jackpot, set your bet, and ride a persistent best-bank.
+Self-contained `index.html`, zero runtime dependencies — runs standalone or in
+an iframe.
+
+**Codename:** `PinkPalaceSlots.aa`
+**Topic hub:** registered in `games-agentabrams` → games.agentabrams.com
+
+## Paytable (× bet)
+💎💎💎 50 · 👑👑👑 25 · 🏎️🏎️🏎️ 15 · 🥂🥂🥂 10 · 🌴🌴🌴 8 · 🌹🌹🌹 5 · two 💎 3
+
+## Controls
+Spin button / Space · ← → set bet · Max · Comp button when you bust.
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..f2eae78
--- /dev/null
+++ b/index.html
@@ -0,0 +1,302 @@
+<!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>Beverly Hills Slots — Pink Palace Jackpot</title>
+<style>
+@import url('https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;900&family=Inter:wght@500;600;700;800&display=swap');
+*{margin:0;padding:0;box-sizing:border-box;}
+html{-webkit-text-size-adjust:100%;text-size-adjust:100%;height:100%;}
+body{
+ touch-action:manipulation;-webkit-tap-highlight-color:transparent;
+ -webkit-user-select:none;user-select:none;-webkit-touch-callout:none;
+}
+button{touch-action:manipulation;-webkit-tap-highlight-color:transparent;}
+:root{
+ --ivory:#efe3c8; --ivory-dk:#c9b07a; --gold:#e9c46a; --gold-hi:#f6de9b;
+ --peach:#f4a261; --burnt:#e76f51; --teal:#2a9d8f; --ink:#1a1410;
+ --green:#41c98a; --font-disp:"Playfair Display",Georgia,serif;
+ --font-body:"Inter",-apple-system,"Segoe UI",Helvetica,Arial,sans-serif;
+}
+html,body{height:100%;}
+body{
+ font-family:var(--font-body); color:var(--ivory);
+ background:
+ radial-gradient(circle at 20% 0%, rgba(233,196,106,.22), transparent 44%),
+ radial-gradient(circle at 100% 100%, rgba(231,111,81,.20), transparent 46%),
+ linear-gradient(160deg,#241a12 0%,#17110c 55%,#0d0907 100%);
+ min-height:100%; display:flex; align-items:center; justify-content:center; padding:clamp(12px,3vw,26px); overflow:hidden;
+}
+.machine{ width:min(440px,100%); }
+
+/* Header */
+.head{ text-align:center; margin-bottom:14px; }
+.kicker{ font-size:11px; letter-spacing:.34em; text-transform:uppercase; color:var(--ivory-dk); }
+.wordmark{
+ font-family:var(--font-disp); font-weight:900; line-height:.98;
+ font-size:clamp(28px,8vw,44px); margin:2px 0;
+ background:linear-gradient(180deg,var(--gold-hi),var(--peach) 72%,var(--burnt));
+ -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent;
+ filter:drop-shadow(0 3px 8px rgba(0,0,0,.4));
+}
+.palms{ font-size:18px; letter-spacing:5px; }
+
+/* Cabinet */
+.cabinet{
+ position:relative; border-radius:22px; padding:clamp(14px,4vw,22px);
+ background:linear-gradient(180deg, rgba(255,255,255,.05), rgba(0,0,0,.2)), linear-gradient(155deg,#2c2118,#1b140e);
+ border:1px solid rgba(233,196,106,.4);
+ box-shadow:0 30px 70px rgba(0,0,0,.6), inset 0 1px 0 rgba(255,255,255,.06);
+}
+.cabinet::before{ content:""; position:absolute; inset:7px; border:1px solid rgba(233,196,106,.2); border-radius:16px; pointer-events:none; }
+
+/* Reels */
+.reels{
+ display:grid; grid-template-columns:repeat(3,1fr); gap:10px;
+ background:linear-gradient(180deg,#0f0b08,#161009); border-radius:16px; padding:12px;
+ border:1px solid rgba(233,196,106,.3); position:relative;
+}
+.reels::after{ /* payline */
+ content:""; position:absolute; left:8px; right:8px; top:50%; height:2px; transform:translateY(-50%);
+ background:linear-gradient(90deg,transparent,rgba(231,111,81,.85),transparent);
+}
+.reel{
+ height:clamp(84px,22vw,108px); border-radius:12px; overflow:hidden; position:relative;
+ background:linear-gradient(180deg,#efe3c8,#d8c290); border:1px solid rgba(0,0,0,.3);
+ box-shadow:inset 0 8px 14px rgba(0,0,0,.25), inset 0 -8px 14px rgba(0,0,0,.25);
+}
+.reel .sym{
+ position:absolute; inset:0; display:flex; align-items:center; justify-content:center;
+ font-size:clamp(40px,11vw,58px); line-height:1;
+ filter:drop-shadow(0 2px 3px rgba(0,0,0,.3));
+}
+.reel.spin .sym{ animation:blur .28s linear infinite; }
+@keyframes blur{ 0%{transform:translateY(-8%);} 100%{transform:translateY(8%);} }
+.reel.win{ box-shadow:0 0 0 2px var(--gold), 0 0 22px rgba(233,196,106,.7), inset 0 8px 14px rgba(0,0,0,.2); }
+
+/* Meters */
+.meters{ display:grid; grid-template-columns:1fr 1fr 1fr; gap:8px; margin:14px 0 4px; }
+.meter{ text-align:center; background:linear-gradient(160deg,rgba(255,255,255,.05),rgba(0,0,0,.2)); border:1px solid rgba(233,196,106,.28); border-radius:12px; padding:9px 4px; }
+.meter .n{ font-family:var(--font-disp); font-weight:900; font-size:clamp(18px,5vw,24px); color:var(--gold); }
+.meter .l{ font-size:9px; letter-spacing:.14em; text-transform:uppercase; color:var(--ivory-dk); margin-top:2px; }
+.meter.win .n{ color:var(--green); }
+
+.msg{ text-align:center; min-height:24px; margin:12px 0 4px; font-family:var(--font-disp); font-weight:700; font-size:clamp(15px,4vw,20px); letter-spacing:.01em; }
+.msg.jackpot{ background:linear-gradient(90deg,var(--gold-hi),var(--peach),var(--gold-hi)); background-size:200% 100%; -webkit-background-clip:text; background-clip:text; -webkit-text-fill-color:transparent; animation:sh 1s linear infinite; }
+@keyframes sh{ from{background-position:200% 0;} to{background-position:-200% 0;} }
+
+/* Controls */
+.controls{ display:flex; align-items:center; gap:10px; margin-top:12px; }
+.bet{ display:flex; align-items:center; gap:6px; }
+.chip-btn{
+ width:38px; height:38px; border-radius:50%; border:1px solid rgba(233,196,106,.5);
+ background:linear-gradient(180deg,rgba(255,255,255,.06),rgba(0,0,0,.3)); color:var(--ivory);
+ font-size:20px; font-weight:800; cursor:pointer; display:flex; align-items:center; justify-content:center;
+ transition:transform .12s, border-color .15s;
+}
+.chip-btn:hover{ border-color:var(--gold); transform:translateY(-1px); }
+.chip-btn:active{ transform:translateY(0); }
+.bet-val{ min-width:64px; text-align:center; }
+.bet-val .b{ font-family:var(--font-disp); font-weight:900; font-size:20px; color:var(--gold); }
+.bet-val .l{ font-size:9px; letter-spacing:.14em; text-transform:uppercase; color:var(--ivory-dk); }
+.spin-btn{
+ flex:1; font-weight:800; font-size:15px; letter-spacing:.1em; text-transform:uppercase; color:var(--ink);
+ cursor:pointer; border:none; padding:15px 10px; border-radius:999px;
+ background:linear-gradient(180deg,var(--gold-hi),var(--peach)); box-shadow:0 12px 26px rgba(0,0,0,.45);
+ transition:transform .12s, filter .12s;
+}
+.spin-btn:hover{ transform:translateY(-2px); filter:brightness(1.06); }
+.spin-btn:active{ transform:translateY(0); }
+.spin-btn:disabled{ filter:grayscale(.5) brightness(.8); cursor:default; transform:none; }
+.maxbet{
+ font-weight:700; font-size:12px; letter-spacing:.08em; text-transform:uppercase; color:var(--ivory);
+ background:transparent; border:1px solid rgba(233,196,106,.4); border-radius:999px; padding:0 14px; height:44px; cursor:pointer;
+}
+.maxbet:hover{ border-color:var(--gold); }
+
+.foot{ text-align:center; font-size:11px; color:var(--ivory-dk); margin-top:12px; letter-spacing:.04em; }
+.foot .gold{ color:var(--gold); }
+.comp{ display:none; margin:10px auto 0; }
+.comp.show{ display:block; }
+
+/* Paytable */
+.pay{ margin-top:10px; font-size:10.5px; color:var(--ivory-dk); text-align:center; line-height:1.7; }
+.pay b{ color:var(--gold); }
+</style>
+</head>
+<body>
+<div class="machine">
+ <div class="head">
+ <div class="kicker">Beverly Hills · 90210</div>
+ <div class="wordmark">Pink Palace Slots</div>
+ <div class="palms">🌴 🎰 🌴</div>
+ </div>
+
+ <div class="cabinet">
+ <div class="reels" id="reels">
+ <div class="reel" id="r0"><div class="sym">💎</div></div>
+ <div class="reel" id="r1"><div class="sym">🌴</div></div>
+ <div class="reel" id="r2"><div class="sym">🥂</div></div>
+ </div>
+
+ <div class="msg" id="msg">Pull for the Pink Palace jackpot.</div>
+
+ <div class="meters">
+ <div class="meter"><div class="n" id="mCredits">500</div><div class="l">Chips</div></div>
+ <div class="meter win"><div class="n" id="mWin">0</div><div class="l">Last Win</div></div>
+ <div class="meter"><div class="n" id="mBest">500</div><div class="l">Best</div></div>
+ </div>
+
+ <div class="controls">
+ <div class="bet">
+ <button class="chip-btn" id="betDown" aria-label="Lower bet">−</button>
+ <div class="bet-val"><div class="b" id="betVal">25</div><div class="l">Bet</div></div>
+ <button class="chip-btn" id="betUp" aria-label="Raise bet">+</button>
+ </div>
+ <button class="spin-btn" id="spinBtn">Spin</button>
+ <button class="maxbet" id="maxBtn">Max</button>
+ </div>
+
+ <button class="spin-btn comp" id="compBtn">🍸 Comp Me 300 Chips</button>
+
+ <div class="pay">
+ <b>💎💎💎</b> 50× · <b>👑👑👑</b> 25× · <b>🏎️🏎️🏎️</b> 15×<br>
+ <b>🥂🥂🥂</b> 10× · <b>🌴🌴🌴</b> 8× · <b>🌹🌹🌹</b> 5× · two 💎 3×
+ </div>
+ </div>
+
+ <div class="foot">← → set bet · Space to spin · <span class="gold">chase the diamonds</span></div>
+</div>
+
+<script>
+(function(){
+ "use strict";
+ var LS_BEST="beverlySlots.best";
+
+ // Weighted reel strip — diamonds rarest.
+ var SYMBOLS=[
+ {s:"💎",w:2, pay:50},
+ {s:"👑",w:3, pay:25},
+ {s:"🏎️",w:4, pay:15},
+ {s:"🥂",w:5, pay:10},
+ {s:"🌴",w:6, pay:8},
+ {s:"🌹",w:7, pay:5}
+ ];
+ var BAG=[]; SYMBOLS.forEach(function(o){ for(var i=0;i<o.w;i++) BAG.push(o); });
+ var PAY={}; SYMBOLS.forEach(function(o){ PAY[o.s]=o.pay; });
+
+ var BETS=[25,50,100,150,200];
+ var betIdx=0;
+ var credits=500, best=parseInt(localStorage.getItem(LS_BEST)||"500",10)||500;
+ var spinning=false, rigged=null;
+
+ var $=function(id){return document.getElementById(id);};
+ var reels=[$("r0"),$("r1"),$("r2")];
+ var symEls=reels.map(function(r){return r.querySelector(".sym");});
+
+ function bet(){ return BETS[betIdx]; }
+ function pick(){ return BAG[(Math.random()*BAG.length)|0]; }
+
+ function render(){
+ $("mCredits").textContent=credits.toLocaleString();
+ $("mBest").textContent=best.toLocaleString();
+ $("betVal").textContent=bet();
+ var broke = credits < BETS[0];
+ $("spinBtn").disabled = spinning || broke;
+ $("betUp").disabled=spinning; $("betDown").disabled=spinning; $("maxBtn").disabled=spinning;
+ $("compBtn").classList.toggle("show", broke && !spinning);
+ }
+
+ function setBet(dir){
+ if(spinning) return;
+ betIdx=Math.max(0, Math.min(BETS.length-1, betIdx+dir));
+ // don't allow a bet larger than the bank
+ while(BETS[betIdx] > credits && betIdx>0) betIdx--;
+ render();
+ }
+ function maxBet(){
+ if(spinning) return;
+ for(var i=BETS.length-1;i>=0;i--){ if(BETS[i]<=credits){ betIdx=i; break; } }
+ render();
+ }
+
+ function spin(){
+ if(spinning || credits < bet()) return;
+ spinning=true;
+ credits -= bet();
+ reels.forEach(function(r){ r.classList.remove("win"); });
+ $("mWin").textContent="0";
+ $("msg").textContent="Spinning…"; $("msg").className="msg";
+ render();
+
+ var result = rigged || [pick().s, pick().s, pick().s];
+ rigged=null;
+
+ // animate: each reel cycles symbols, stops staggered
+ var stops=[650, 900, 1180];
+ reels.forEach(function(r,i){
+ r.classList.add("spin");
+ var cyc=setInterval(function(){ symEls[i].textContent=pick().s; }, 70);
+ setTimeout(function(){
+ clearInterval(cyc);
+ r.classList.remove("spin");
+ symEls[i].textContent=result[i];
+ if(i===2) setTimeout(function(){ resolve(result); }, 120);
+ }, stops[i]);
+ });
+ }
+
+ function resolve(res){
+ var win=0, msg="", cls="msg", winReels=[];
+ if(res[0]===res[1] && res[1]===res[2]){
+ win = bet() * PAY[res[0]];
+ winReels=[0,1,2];
+ if(res[0]==="💎"){ msg="💎 PINK PALACE JACKPOT! +"+win.toLocaleString(); cls="msg jackpot"; }
+ else msg="Triple "+res[0]+" — +"+win.toLocaleString();
+ } else {
+ // two diamonds anywhere pays 3x
+ var dia = res.filter(function(s){return s==="💎";}).length;
+ if(dia===2){ win=bet()*3; msg="Two 💎 — +"+win.toLocaleString();
+ res.forEach(function(s,i){ if(s==="💎") winReels.push(i); });
+ } else { msg = pickTaunt(); }
+ }
+
+ if(win>0){
+ credits += win;
+ $("mWin").textContent=win.toLocaleString();
+ winReels.forEach(function(i){ reels[i].classList.add("win"); });
+ if(credits>best){ best=credits; localStorage.setItem(LS_BEST,String(best)); }
+ }
+ $("msg").textContent=msg; $("msg").className=cls;
+ spinning=false;
+ render();
+ }
+
+ var TAUNTS=["Valet's still parking your luck.","Not this pull — try Rodeo again.","So close. Spin it back.","The Palace keeps the house edge.","Almost A-list. Again?"];
+ function pickTaunt(){ return TAUNTS[(Math.random()*TAUNTS.length)|0]; }
+
+ // wire
+ $("spinBtn").addEventListener("click", spin);
+ $("betUp").addEventListener("click", function(){ setBet(1); });
+ $("betDown").addEventListener("click", function(){ setBet(-1); });
+ $("maxBtn").addEventListener("click", maxBet);
+ $("compBtn").addEventListener("click", function(){ credits+=300; if(betIdx>0&&BETS[betIdx]>credits) betIdx=0; $("msg").textContent="🍸 On the house — 300 chips. Good luck."; $("msg").className="msg"; render(); });
+ document.addEventListener("keydown", function(e){
+ if(e.key===" "||e.key==="Enter"){ e.preventDefault(); spin(); }
+ else if(e.key==="ArrowUp"||e.key==="ArrowRight"){ setBet(1); }
+ else if(e.key==="ArrowDown"||e.key==="ArrowLeft"){ setBet(-1); }
+ });
+
+ render();
+
+ // Automation/test hook (mirrors other hub games).
+ window.__slots={
+ spin:spin,
+ rig:function(arr){ rigged=arr.slice(0,3); }, // force next result, e.g. ["💎","💎","💎"]
+ state:function(){ return { credits:credits, bet:bet(), spinning:spinning, best:best, lastWin:parseInt($("mWin").textContent.replace(/,/g,""),10)||0, reels:symEls.map(function(e){return e.textContent;}), msg:$("msg").textContent }; }
+ };
+})();
+</script>
+</body>
+</html>
(oldest)
·
back to Beverly Hills Slots
·
(newest)