Tired of boilerplate code and endless configuration files? Same here.
I built this demo specifically to showcase how straightforward the implementation of "Quantum Game" can be. No hidden dependencies, no complex setup—just clean code that does exactly what it says on the tin.
It’s genuinely effortless to incorporate into your existing projects. Simplicity was the main feature here.
Grab the code:
<!-- INICIO WIDGET RPSLS (RESPONSIVE 9:16) -->
<div id="rpsls-wrapper" class="w-full flex justify-center items-center py-4 md:py-10" style="background: transparent;">
<!-- Dependencias (Tailwind + Fuentes) -->
<script src="https://cdn.tailwindcss.com"></script>
<link href="https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700;900&family=Rajdhani:wght@300;500;700&display=swap" rel="stylesheet">
<style>
/* Estilos Scoped para el Widget */
#rpsls-wrapper {
font-family: 'Rajdhani', sans-serif;
color: white;
--neon-blue: #00f3ff;
--neon-pink: #ff00ff;
--neon-green: #00ff9d;
--neon-red: #ff3c3c;
--glass-bg: rgba(15, 23, 42, 0.95);
--glass-border: rgba(255, 255, 255, 0.1);
}
#game-container {
position: relative;
width: 100%;
max-width: 500px; /* Optimizado para ancho m贸vil/vertical */
/* En escritorio se ver谩 como una 'carta' vertical elegante */
min-height: 80vh; /* Ocupa buena altura en m贸vil */
max-height: 900px;
background: radial-gradient(circle at center, #1e293b 0%, #020617 100%);
border-radius: 20px;
border: 1px solid var(--glass-border);
box-shadow: 0 0 50px rgba(0, 243, 255, 0.1), inset 0 0 100px rgba(0,0,0,0.5);
overflow: hidden;
user-select: none;
display: flex;
flex-direction: column;
}
/* En pantallas grandes, permitimos que sea un poco m谩s ancho si se desea,
pero mantenemos la est茅tica vertical para la consistencia solicitada */
@media (min-width: 768px) {
#game-container {
max-width: 800px;
min-height: 600px;
}
}
.scanlines {
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: linear-gradient(to bottom, rgba(255,255,255,0), rgba(255,255,255,0) 50%, rgba(0,0,0,0.2) 50%, rgba(0,0,0,0.2));
background-size: 100% 4px;
pointer-events: none;
z-index: 10;
opacity: 0.3;
}
.neon-text {
font-family: 'Orbitron', sans-serif;
text-shadow: 0 0 10px var(--neon-blue);
}
.neon-text-danger {
text-shadow: 0 0 10px var(--neon-red);
}
.hex-btn {
width: 60px; /* Ligeramente m谩s peque帽os para asegurar que quepan 5 */
height: 60px;
background: rgba(255, 255, 255, 0.05);
clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
display: flex;
justify-content: center;
align-items: center;
transition: all 0.2s ease;
cursor: pointer;
border: none;
outline: none;
color: var(--neon-blue);
position: relative;
margin: 0 2px; /* Espaciado ajustado */
}
@media (min-width: 768px) {
.hex-btn { width: 70px; height: 70px; margin: 0 8px; }
}
.hex-btn:hover:not(:disabled) {
background: rgba(0, 243, 255, 0.2);
transform: scale(1.1);
filter: drop-shadow(0 0 8px var(--neon-blue));
color: white;
z-index: 20;
}
.hex-btn:active:not(:disabled) {
transform: scale(0.95);
}
.hex-btn:disabled {
opacity: 0.3;
cursor: not-allowed;
filter: grayscale(1);
}
.hex-btn svg {
width: 30px; /* Ajuste para m贸vil */
height: 30px;
fill: currentColor;
}
@media (min-width: 768px) { .hex-btn svg { width: 36px; height: 36px; } }
.btn-label {
font-family: 'Orbitron', sans-serif;
font-size: 9px;
letter-spacing: 1px;
color: var(--neon-blue);
margin-top: 4px;
text-shadow: 0 0 2px black;
opacity: 0.7;
transition: opacity 0.2s;
}
.control-group:hover .btn-label {
opacity: 1;
color: white;
text-shadow: 0 0 5px var(--neon-blue);
}
@keyframes pulse-red {
0% { box-shadow: 0 0 0 0 rgba(255, 60, 60, 0.4); }
70% { box-shadow: 0 0 0 20px rgba(255, 60, 60, 0); }
100% { box-shadow: 0 0 0 0 rgba(255, 60, 60, 0); }
}
.timer-active {
animation: pulse-red 1s infinite;
color: var(--neon-red) !important;
}
/* Animaciones ajustadas para verticalidad */
@keyframes slide-in-bottom {
from { transform: translateY(100%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
@keyframes slide-in-top {
from { transform: translateY(-100%); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
/* Mantener laterales para desktop */
@keyframes slide-in-left { from { transform: translateX(-100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
@keyframes slide-in-right { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } }
.player-hand-anim { animation: slide-in-bottom 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; }
.ai-hand-anim { animation: slide-in-top 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; }
@media (min-width: 768px) {
.player-hand-anim { animation: slide-in-left 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; }
.ai-hand-anim { animation: slide-in-right 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275) forwards; }
}
.result-icon {
width: 80px; /* M谩s peque帽o en m贸vil */
height: 80px;
fill: white;
filter: drop-shadow(0 0 15px currentColor);
}
@media (min-width: 768px) { .result-icon { width: 120px; height: 120px; } }
.overlay-screen {
position: absolute;
inset: 0;
background: rgba(0,0,0,0.85);
backdrop-filter: blur(8px);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
z-index: 50;
transition: opacity 0.3s;
padding: 20px; /* Padding extra para no pegar bordes */
}
.hidden { display: none !important; }
.cy-btn {
background: transparent;
border: 2px solid var(--neon-blue);
color: var(--neon-blue);
padding: 12px 30px;
font-family: 'Orbitron', sans-serif;
font-size: 1rem;
text-transform: uppercase;
letter-spacing: 2px;
cursor: pointer;
position: relative;
overflow: hidden;
transition: 0.3s;
clip-path: polygon(10% 0, 100% 0, 100% 80%, 90% 100%, 0 100%, 0 20%);
}
.cy-btn:hover { background: var(--neon-blue); color: black; box-shadow: 0 0 20px var(--neon-blue); }
.cy-btn.red { border-color: var(--neon-red); color: var(--neon-red); }
.cy-btn.red:hover { background: var(--neon-red); color: white; box-shadow: 0 0 20px var(--neon-red); }
.reveal-btn {
background: var(--neon-green);
color: black;
border: none;
font-weight: 900;
animation: pulse-green 1s infinite;
position: absolute;
top: 50%; /* Centrado en m贸vil */
left: 50%;
transform: translate(-50%, -50%);
z-index: 60;
padding: 10px 20px;
font-family: 'Orbitron', sans-serif;
font-size: 1.2rem;
cursor: pointer;
box-shadow: 0 0 20px var(--neon-green);
clip-path: polygon(10% 0, 100% 0, 100% 80%, 90% 100%, 0 100%, 0 20%);
width: max-content;
}
.reveal-btn:hover { background: white; box-shadow: 0 0 30px white; }
.rules-btn-small {
font-family: 'Orbitron', sans-serif;
font-size: 0.6rem;
letter-spacing: 1px;
color: var(--neon-blue);
border: 1px solid var(--neon-blue);
padding: 4px 10px;
background: rgba(0, 243, 255, 0.1);
cursor: pointer;
transition: all 0.2s;
text-transform: uppercase;
margin-top: 5px;
}
.rules-btn-small:hover { background: var(--neon-blue); color: black; box-shadow: 0 0 10px var(--neon-blue); }
.rules-content {
background: rgba(15, 23, 42, 0.98);
border: 1px solid var(--neon-blue);
box-shadow: 0 0 40px rgba(0, 243, 255, 0.15);
max-width: 500px;
width: 95%;
padding: 1.5rem;
border-radius: 8px;
position: relative;
max-height: 80vh;
overflow-y: auto;
}
.close-rules {
position: absolute;
top: 5px;
right: 10px;
color: var(--neon-red);
font-size: 1.5rem;
cursor: pointer;
transition: transform 0.2s;
background: none;
border: none;
font-family: 'Orbitron', sans-serif;
}
.close-rules:hover { transform: scale(1.2); text-shadow: 0 0 10px var(--neon-red); }
@keyframes pulse-green {
0% { transform: translate(-50%, -50%) scale(1); box-shadow: 0 0 0 0 rgba(0, 255, 157, 0.7); }
70% { transform: translate(-50%, -50%) scale(1.05); box-shadow: 0 0 0 15px rgba(0, 255, 157, 0); }
100% { transform: translate(-50%, -50%) scale(1); box-shadow: 0 0 0 0 rgba(0, 255, 157, 0); }
}
.particle {
position: absolute;
width: 2px;
height: 2px;
background: white;
border-radius: 50%;
animation: float 10s infinite linear;
opacity: 0.3;
}
@keyframes float {
0% { transform: translateY(0) rotate(0deg); }
100% { transform: translateY(-600px) rotate(360deg); }
}
#rules-diagram {
position: absolute;
top: 15%; /* Bajado un poco para no chocar con header */
left: 50%;
transform: translateX(-50%);
width: 240px; /* M谩s grande para que llene el fondo */
height: 240px;
z-index: 15;
opacity: 0.15; /* M谩s sutil */
pointer-events: none;
animation: hologram-flicker 4s infinite;
}
@keyframes hologram-flicker {
0%, 100% { opacity: 0.15; }
50% { opacity: 0.10; }
52% { opacity: 0.05; }
54% { opacity: 0.15; }
}
.rule-icon { fill: var(--neon-blue); }
.rule-line { stroke: var(--neon-blue); stroke-width: 1.5; stroke-opacity: 0.5; fill: none; }
.rule-arrow { fill: var(--neon-blue); fill-opacity: 0.5; }
/* Battle Choice Displays */
.battle-circle {
width: 100px; height: 100px; /* Default mobile */
background: rgba(31, 41, 55, 0.5);
border-radius: 9999px;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 0 30px rgba(0,0,0,0.2);
}
@media (min-width: 768px) { .battle-circle { width: 140px; height: 140px; } }
</style>
<div id="game-container">
<div class="scanlines"></div>
<div id="particles-container"></div>
<!-- Header Compacto -->
<div class="absolute top-0 left-0 w-full p-4 flex justify-between items-start z-30">
<div class="max-w-[60%]">
<h2 class="text-[10px] text-gray-400 tracking-widest uppercase">SYSTEM STATUS</h2>
<div id="status-text" class="text-sm md:text-xl font-bold text-cyan-300 leading-tight">AWAITING PLAYER...</div>
<div id="status-detail" class="text-xs text-cyan-200 font-mono mt-1 tracking-wider h-8 opacity-80 uppercase leading-tight"></div>
</div>
<div class="text-right flex flex-col items-end">
<h2 class="text-[10px] text-gray-400 tracking-widest uppercase">STREAK</h2>
<div id="streak-display" class="text-3xl md:text-4xl font-black neon-text text-white leading-none">0</div>
<button onclick="openRules()" class="rules-btn-small">RULES</button>
</div>
</div>
<!-- Rules Hologram (Fondo) -->
<div id="rules-diagram">
<svg viewBox="0 0 200 200">
<defs>
<marker id="arrow" markerWidth="6" markerHeight="6" refX="5" refY="3" orient="auto" class="rule-arrow">
<path d="M0,0 L0,6 L6,3 z" fill="currentColor" />
</marker>
</defs>
<path class="rule-line" marker-end="url(#arrow)" d="M100,30 L166,78" />
<path class="rule-line" marker-end="url(#arrow)" d="M166,78 L141,155" />
<path class="rule-line" marker-end="url(#arrow)" d="M141,155 L59,155" />
<path class="rule-line" marker-end="url(#arrow)" d="M59,155 L34,78" />
<path class="rule-line" marker-end="url(#arrow)" d="M34,78 L100,30" />
<path class="rule-line" marker-end="url(#arrow)" d="M100,30 L59,155" />
<path class="rule-line" marker-end="url(#arrow)" d="M59,155 L166,78" />
<path class="rule-line" marker-end="url(#arrow)" d="M166,78 L34,78" />
<path class="rule-line" marker-end="url(#arrow)" d="M34,78 L141,155" />
<path class="rule-line" marker-end="url(#arrow)" d="M141,155 L100,30" />
<g transform="translate(88, 10) scale(0.05)" class="rule-icon"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></g>
<g transform="translate(160, 60) scale(0.04)" class="rule-icon"><path d="M384 32H128c-17.7 0-32 14.3-32 32s14.3 32 32 32h256c17.7 0 32 14.3 32 32v256c0 17.7 14.3 32 32 32s32-14.3 32-32V64c0-35.3-28.7-64-64-64z M96 128H32c-17.7 0-32 14.3-32 32v320c0 17.7 14.3 32 32 32h256c17.7 0 32-14.3 32-32V160c0-17.7-14.3-32-32-32H96z"/></g>
<g transform="translate(135, 150) scale(0.04)" class="rule-icon"><path d="M152 104 C104 112 64 152 56 200 C48 248 24 280 24 336 C24 400 80 456 144 456 C184 456 216 432 248 432 C280 432 312 456 352 456 C416 456 472 400 472 336 C472 280 448 248 440 200 C432 152 392 112 344 104 C296 96 200 96 152 104 Z"/></g>
<g transform="translate(45, 150) scale(0.04)" class="rule-icon"><path d="M160 32C160 32 192 64 192 96C192 120 176 136 160 144C160 144 256 160 288 224C304 256 288 288 288 288C288 288 352 288 384 320C416 352 416 416 384 448L352 416C368 400 368 368 352 352C336 336 304 336 304 336C304 336 320 400 288 432L256 400C272 384 272 352 256 320C240 288 208 272 208 272L208 368L160 368L160 272C160 272 128 288 112 320C96 352 96 384 112 400L80 432C48 400 64 336 64 336C64 336 32 336 16 352C0 368 0 400 16 416L48 448C16 416 16 352 48 320C80 288 144 288 144 288C144 288 128 256 144 224C176 160 272 144 272 144C256 136 240 120 240 96C240 64 272 32 272 32L160 32Z"/></g>
<g transform="translate(18, 60) scale(0.04)" class="rule-icon"><path d="M144 64c0-26.5 21.5-48 48-48h16c26.5 0 48 21.5 48 48v224h16V32c0-17.7 14.3-32 32-32h16c17.7 0 32 14.3 32 32v256h16V64c0-17.7 14.3-32 32-32h16c17.7 0 32 14.3 32 32v248.2c0 73.6-25.5 145.4-72.1 204.6l-5.4 6.9c-23.7 30.1-66.7 40.5-101.4 24.6l-85.9-39.2C54.6 492.3 32 464.2 32 432V176c0-17.7 14.3-32 32-32h16c17.7 0 32 14.3 32 32v112h16V64z"/></g>
</svg>
</div>
<!-- Rules Modal -->
<div id="rules-modal" class="overlay-screen hidden z-50">
<div class="rules-content">
<button onclick="closeRules()" class="close-rules">X</button>
<h2 class="text-xl md:text-2xl font-bold neon-text mb-4 text-center tracking-widest">COMBAT PROTOCOLS</h2>
<div class="grid grid-cols-1 gap-2 text-xs md:text-sm text-gray-300 font-mono overflow-y-auto max-h-[60vh]">
<div class="flex items-center gap-2"><span class="text-cyan-400 font-bold w-16 md:w-20">SCISSORS</span> <span>cuts Paper, decapitates Lizard</span></div>
<div class="flex items-center gap-2"><span class="text-cyan-400 font-bold w-16 md:w-20">PAPER</span> <span>covers Rock, disproves Spock</span></div>
<div class="flex items-center gap-2"><span class="text-cyan-400 font-bold w-16 md:w-20">ROCK</span> <span>crushes Lizard, crushes Scissors</span></div>
<div class="flex items-center gap-2"><span class="text-cyan-400 font-bold w-16 md:w-20">LIZARD</span> <span>poisons Spock, eats Paper</span></div>
<div class="flex items-center gap-2"><span class="text-cyan-400 font-bold w-16 md:w-20">SPOCK</span> <span>smashes Scissors, vaporizes Rock</span></div>
</div>
</div>
</div>
<div id="start-screen" class="overlay-screen">
<h1 class="text-4xl md:text-6xl font-black mb-2 neon-text text-center italic">R.P.S.L.S.</h1>
<p class="text-cyan-200 tracking-widest mb-8 text-xs md:text-sm">RANDOM BATTLE PROTOCOL</p>
<button class="cy-btn" onclick="startGame()">INITIATE SYSTEM</button>
<div class="mt-8 flex gap-4 opacity-50">
<div class="w-2 h-2 bg-cyan-500 rounded-full animate-pulse"></div>
<div class="w-2 h-2 bg-cyan-500 rounded-full animate-pulse delay-75"></div>
<div class="w-2 h-2 bg-cyan-500 rounded-full animate-pulse delay-150"></div>
</div>
</div>
<div id="game-over-screen" class="overlay-screen hidden">
<h1 class="text-5xl md:text-6xl font-black mb-2 neon-text-danger italic text-center">DEFEAT</h1>
<p class="text-gray-300 mb-2 text-center text-sm md:text-base">AI HAS OUTSMARTED YOU</p>
<div class="bg-red-900/30 border border-red-500/50 p-4 rounded mb-8 text-center">
<span class="block text-xs uppercase tracking-widest text-red-300">FINAL STREAK</span>
<span id="final-score" class="text-4xl font-bold text-white">0</span>
</div>
<button class="cy-btn red" onclick="resetGame()">SYSTEM REBOOT</button>
</div>
<!-- AREA DE JUEGO CENTRAL (FLEXIBLE) -->
<div class="absolute inset-0 flex flex-col justify-center z-20 pt-20 pb-20 md:pt-10 md:pb-10">
<!-- Zona de Batalla (Resultados) -->
<!-- Mobile: Stacked Vertical (Reverse for visual logic: Enemy Top, VS, You Bottom) -->
<!-- Desktop: Row -->
<div id="battle-area" class="flex flex-col-reverse md:flex-row justify-center items-center w-full px-4 gap-4 md:gap-16 mb-4 md:mb-8 opacity-0 transition-opacity duration-300 flex-1">
<!-- Player (Bottom in Mobile) -->
<div class="text-center order-1 md:order-none">
<div id="player-choice-display" class="battle-circle border-2 border-cyan-500 shadow-[0_0_30px_rgba(0,243,255,0.2)]">
<!-- Icon -->
</div>
<p class="text-[10px] md:text-xs tracking-widest text-cyan-400 mt-2">YOU</p>
</div>
<!-- VS / Result -->
<div class="flex flex-col items-center justify-center order-2 md:order-none my-2 md:my-0">
<div id="result-message" class="text-3xl md:text-4xl font-black italic neon-text mb-1 text-center">VS</div>
<div id="result-detail" class="text-[10px] md:text-xs text-gray-400 uppercase tracking-widest text-center max-w-[150px] leading-tight"></div>
</div>
<!-- AI (Top in Mobile) -->
<div class="text-center order-3 md:order-none">
<p class="text-[10px] md:text-xs tracking-widest text-pink-400 mb-2">AI (CPU)</p>
<div id="ai-choice-display" class="battle-circle border-2 border-pink-500 shadow-[0_0_30px_rgba(255,0,255,0.2)]">
<!-- Icon -->
</div>
</div>
</div>
<!-- Countdown -->
<div id="countdown-display" class="text-6xl md:text-8xl font-black text-white absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 hidden z-40 neon-text">
5
</div>
<button id="reveal-btn" class="reveal-btn hidden" onclick="triggerReveal()">REVEAL!</button>
<!-- CONTROLES (Bottom) -->
<div id="controls-area" class="absolute bottom-4 left-0 w-full flex flex-wrap justify-center gap-2 px-2 transition-all duration-300 transform translate-y-20 opacity-0 z-30">
<div class="flex flex-col items-center control-group">
<button class="hex-btn" onclick="makeMove('rock')">
<svg viewBox="0 0 512 512"><path d="M152 104 C104 112 64 152 56 200 C48 248 24 280 24 336 C24 400 80 456 144 456 C184 456 216 432 248 432 C280 432 312 456 352 456 C416 456 472 400 472 336 C472 280 448 248 440 200 C432 152 392 112 344 104 C296 96 200 96 152 104 Z"/></svg>
</button>
<span class="btn-label">ROCK</span>
</div>
<div class="flex flex-col items-center control-group">
<button class="hex-btn" onclick="makeMove('paper')">
<svg viewBox="0 0 512 512"><path d="M384 32H128c-17.7 0-32 14.3-32 32s14.3 32 32 32h256c17.7 0 32 14.3 32 32v256c0 17.7 14.3 32 32 32s32-14.3 32-32V64c0-35.3-28.7-64-64-64z M96 128H32c-17.7 0-32 14.3-32 32v320c0 17.7 14.3 32 32 32h256c17.7 0 32-14.3 32-32V160c0-17.7-14.3-32-32-32H96z"/></svg>
</button>
<span class="btn-label">PAPER</span>
</div>
<div class="flex flex-col items-center control-group">
<button class="hex-btn" onclick="makeMove('scissors')">
<svg viewBox="0 0 384 512"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>
</button>
<span class="btn-label">SCISSORS</span>
</div>
<div class="flex flex-col items-center control-group">
<button class="hex-btn" onclick="makeMove('lizard')">
<svg viewBox="0 0 512 512"><path d="M160 32C160 32 192 64 192 96C192 120 176 136 160 144C160 144 256 160 288 224C304 256 288 288 288 288C288 288 352 288 384 320C416 352 416 416 384 448L352 416C368 400 368 368 352 352C336 336 304 336 304 336C304 336 320 400 288 432L256 400C272 384 272 352 256 320C240 288 208 272 208 272L208 368L160 368L160 272C160 272 128 288 112 320C96 352 96 384 112 400L80 432C48 400 64 336 64 336C64 336 32 336 16 352C0 368 0 400 16 416L48 448C16 416 16 352 48 320C80 288 144 288 144 288C144 288 128 256 144 224C176 160 272 144 272 144C256 136 240 120 240 96C240 64 272 32 272 32L160 32Z"/></svg>
</button>
<span class="btn-label">LIZARD</span>
</div>
<div class="flex flex-col items-center control-group">
<button class="hex-btn" onclick="makeMove('spock')">
<svg viewBox="0 0 512 512"><path d="M144 64c0-26.5 21.5-48 48-48h16c26.5 0 48 21.5 48 48v224h16V32c0-17.7 14.3-32 32-32h16c17.7 0 32 14.3 32 32v256h16V64c0-17.7 14.3-32 32-32h16c17.7 0 32 14.3 32 32v248.2c0 73.6-25.5 145.4-72.1 204.6l-5.4 6.9c-23.7 30.1-66.7 40.5-101.4 24.6l-85.9-39.2C54.6 492.3 32 464.2 32 432V176c0-17.7 14.3-32 32-32h16c17.7 0 32 14.3 32 32v112h16V64z"/></svg>
</button>
<span class="btn-label">SPOCK</span>
</div>
</div>
</div>
</div>
<script>
const rules = {
rock: { beats: ['scissors', 'lizard'], verbs: ['crushes', 'crushes'] },
paper: { beats: ['rock', 'spock'], verbs: ['covers', 'disproves'] },
scissors: { beats: ['paper', 'lizard'], verbs: ['cuts', 'decapitates'] },
lizard: { beats: ['spock', 'paper'], verbs: ['poisons', 'eats'] },
spock: { beats: ['scissors', 'rock'], verbs: ['smashes', 'vaporizes'] }
};
const iconsSVG = {
rock: '<svg class="result-icon" viewBox="0 0 512 512"><path d="M152 104 C104 112 64 152 56 200 C48 248 24 280 24 336 C24 400 80 456 144 456 C184 456 216 432 248 432 C280 432 312 456 352 456 C416 456 472 400 472 336 C472 280 448 248 440 200 C432 152 392 112 344 104 C296 96 200 96 152 104 Z"/></svg>',
paper: '<svg class="result-icon" viewBox="0 0 512 512"><path d="M384 32H128c-17.7 0-32 14.3-32 32s14.3 32 32 32h256c17.7 0 32 14.3 32 32v256c0 17.7 14.3 32 32 32s32-14.3 32-32V64c0-35.3-28.7-64-64-64z M96 128H32c-17.7 0-32 14.3-32 32v320c0 17.7 14.3 32 32 32h256c17.7 0 32-14.3 32-32V160c0-17.7-14.3-32-32-32H96z"/></svg>',
scissors: '<svg class="result-icon" viewBox="0 0 384 512"><path d="M342.6 150.6c12.5-12.5 12.5-32.8 0-45.3s-32.8-12.5-45.3 0L192 210.7 86.6 105.4c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L146.7 256 41.4 361.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L192 301.3 297.4 406.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3L237.3 256 342.6 150.6z"/></svg>',
lizard: '<svg class="result-icon" viewBox="0 0 512 512"><path d="M160 32C160 32 192 64 192 96C192 120 176 136 160 144C160 144 256 160 288 224C304 256 288 288 288 288C288 288 352 288 384 320C416 352 416 416 384 448L352 416C368 400 368 368 352 352C336 336 304 336 304 336C304 336 320 400 288 432L256 400C272 384 272 352 256 320C240 288 208 272 208 272L208 368L160 368L160 272C160 272 128 288 112 320C96 352 96 384 112 400L80 432C48 400 64 336 64 336C64 336 32 336 16 352C0 368 0 400 16 416L48 448C16 416 16 352 48 320C80 288 144 288 144 288C144 288 128 256 144 224C176 160 272 144 272 144C256 136 240 120 240 96C240 64 272 32 272 32L160 32Z"/></svg>',
spock: '<svg class="result-icon" viewBox="0 0 512 512"><path d="M144 64c0-26.5 21.5-48 48-48h16c26.5 0 48 21.5 48 48v224h16V32c0-17.7 14.3-32 32-32h16c17.7 0 32 14.3 32 32v256h16V64c0-17.7 14.3-32 32-32h16c17.7 0 32 14.3 32 32v248.2c0 73.6-25.5 145.4-72.1 204.6l-5.4 6.9c-23.7 30.1-66.7 40.5-101.4 24.6l-85.9-39.2C54.6 492.3 32 464.2 32 432V176c0-17.7 14.3-32 32-32h16c17.7 0 32 14.3 32 32v112h16V64z"/></svg>'
};
let streak = 0;
let countdownValue = 5;
let countdownInterval;
let isPlaying = false;
let playerChoice = null;
const els = {
startScreen: document.getElementById('start-screen'),
gameOverScreen: document.getElementById('game-over-screen'),
countdown: document.getElementById('countdown-display'),
controls: document.getElementById('controls-area'),
statusText: document.getElementById('status-text'),
statusDetail: document.getElementById('status-detail'),
streakDisplay: document.getElementById('streak-display'),
battleArea: document.getElementById('battle-area'),
playerDisplay: document.getElementById('player-choice-display'),
aiDisplay: document.getElementById('ai-choice-display'),
resultMessage: document.getElementById('result-message'),
resultDetail: document.getElementById('result-detail'),
finalScore: document.getElementById('final-score'),
buttons: document.querySelectorAll('.hex-btn'),
revealBtn: document.getElementById('reveal-btn'),
rulesModal: document.getElementById('rules-modal')
};
function startGame() {
els.startScreen.classList.add('hidden');
streak = 0;
updateStreakUI();
startRound();
}
function resetGame() {
els.gameOverScreen.classList.add('hidden');
streak = 0;
updateStreakUI();
els.battleArea.style.opacity = '0';
startRound();
}
function startRound() {
isPlaying = true;
playerChoice = null;
els.battleArea.style.opacity = '0';
els.revealBtn.classList.add('hidden');
els.statusText.innerText = "SYSTEM ARMED. SELECT WEAPON.";
els.statusDetail.innerText = "";
els.statusText.classList.remove('text-red-500');
els.statusText.classList.add('text-cyan-300');
els.controls.classList.remove('translate-y-20', 'opacity-0');
els.buttons.forEach(btn => {
btn.disabled = false;
btn.style.opacity = "1";
});
countdownValue = 5;
els.countdown.innerText = countdownValue;
els.countdown.classList.remove('hidden');
els.countdown.classList.add('timer-active');
clearInterval(countdownInterval);
countdownInterval = setInterval(() => {
countdownValue--;
if(countdownValue > 0) {
els.countdown.innerText = countdownValue;
} else if (countdownValue === 0) {
els.countdown.innerText = "0";
clearInterval(countdownInterval);
if(playerChoice) {
resolveRound();
} else {
handleTimeOut();
}
}
}, 1000);
}
function makeMove(selection) {
if (!isPlaying || playerChoice) return;
playerChoice = selection;
els.buttons.forEach(btn => btn.disabled = true);
els.statusText.innerText = "LOCKED IN. AWAITING REVEAL...";
els.revealBtn.classList.remove('hidden');
}
function triggerReveal() {
if (!playerChoice) return;
clearInterval(countdownInterval);
resolveRound();
}
function resolveRound() {
els.countdown.classList.add('hidden');
els.revealBtn.classList.add('hidden');
els.controls.classList.add('translate-y-20', 'opacity-0');
const options = Object.keys(rules);
const aiSelection = options[Math.floor(Math.random() * options.length)];
const player = playerChoice;
els.battleArea.style.opacity = '1';
els.playerDisplay.innerHTML = iconsSVG[player];
els.aiDisplay.innerHTML = iconsSVG[aiSelection];
els.playerDisplay.classList.remove('player-hand-anim');
els.aiDisplay.classList.remove('ai-hand-anim');
void els.playerDisplay.offsetWidth;
els.playerDisplay.classList.add('player-hand-anim');
els.aiDisplay.classList.add('ai-hand-anim');
if (player === aiSelection) {
els.statusText.innerText = "INTERFERENCE DETECTED";
els.statusDetail.innerText = "WEAPON MATCH - NO EFFECT";
els.resultMessage.innerText = "DRAW";
els.resultMessage.style.color = "#fbbf24";
els.resultDetail.innerText = "REBOOTING PROTOCOL...";
setTimeout(startRound, 2500);
}
else if (rules[player].beats.includes(aiSelection)) {
streak++;
updateStreakUI();
els.statusText.innerText = "THREAT NEUTRALIZED";
const index = rules[player].beats.indexOf(aiSelection);
const verb = rules[player].verbs[index];
const detailText = `${player.toUpperCase()} ${verb.toUpperCase()} ${aiSelection.toUpperCase()}`;
els.statusDetail.innerText = detailText;
els.resultMessage.innerText = "VICTORY";
els.resultMessage.style.color = "#00ff9d";
els.resultDetail.innerText = detailText;
setTimeout(startRound, 2500);
}
else {
els.statusText.innerText = "CRITICAL SYSTEM FAILURE";
const index = rules[aiSelection].beats.indexOf(player);
const verb = rules[aiSelection].verbs[index];
const detailText = `${aiSelection.toUpperCase()} ${verb.toUpperCase()} ${player.toUpperCase()}`;
els.statusDetail.innerText = detailText;
els.resultMessage.innerText = "DEFEAT";
els.resultMessage.style.color = "#ff3c3c";
els.resultDetail.innerText = detailText;
setTimeout(() => triggerGameOver(), 2000);
}
}
function handleTimeOut() {
els.statusText.innerText = "TIME EXPIRED";
els.statusDetail.innerText = "NO INPUT DETECTED";
els.countdown.classList.add('hidden');
els.revealBtn.classList.add('hidden');
els.controls.classList.add('translate-y-20', 'opacity-0');
triggerGameOver();
}
function triggerGameOver() {
els.finalScore.innerText = streak;
els.gameOverScreen.classList.remove('hidden');
}
function updateStreakUI() {
els.streakDisplay.innerText = streak;
els.streakDisplay.style.transform = "scale(1.5)";
setTimeout(() => els.streakDisplay.style.transform = "scale(1)", 200);
}
function openRules() {
els.rulesModal.classList.remove('hidden');
}
function closeRules() {
els.rulesModal.classList.add('hidden');
}
const particleContainer = document.getElementById('particles-container');
for(let i=0; i<20; i++) {
let p = document.createElement('div');
p.classList.add('particle');
p.style.left = Math.random() * 100 + '%';
p.style.top = Math.random() * 100 + '%';
p.style.animationDelay = Math.random() * 5 + 's';
p.style.opacity = Math.random();
particleContainer.appendChild(p);
}
</script>
</div>
<!-- FIN WIDGET RPSLS (RESPONSIVE 9:16) -->
.jpg)