:root {
--gen-green: #00ff9d;
}
* {
transition-property: color, background-color, border-color, text-decoration-color, fill, stroke;
transition-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
transition-duration: 150ms;
}
body {
font-family: 'Inter', system_ui, sans-serif;
}
.title-font {
font-family: 'Space Grotesk', sans-serif;
}
.hero-bg {
background: linear-gradient(135deg, #0a0a0a 0%, #1a1a2e 100%);
}
.coin-container {
perspective: 1200px;
width: 280px;
height: 280px;
margin: 0 auto;
}
.coin {
position: relative;
width: 100%;
height: 100%;
transform-style: preserve-3d;
transition: transform 3.2s cubic-bezier(0.25, 0.1, 0.25, 1);
cursor: pointer;
}
.coin.flipping {
animation: flipCoin 3.2s cubic-bezier(0.25, 0.1, 0.25, 1) forwards;
}
.coin-face {
position: absolute;
width: 100%;
height: 100%;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
box-shadow:
0 0 60px -10px var(--gen-green),
inset 0 0 60px -20px rgba(0, 255, 157, 0.5);
backface-visibility: hidden;
border: 12px solid #111;
}
.coin-heads {
background: linear-gradient(145deg, #facc15, #eab308);
transform: rotateY(0deg);
}
.coin-tails {
background: linear-gradient(145deg, #f1f5f9, #cbd5e1);
transform: rotateY(180deg);
}
.coin-label {
font-size: 6rem;
font-weight: 700;
text-shadow:
0 10px 20px rgba(0, 0, 0, 0.3),
0 0 40px rgba(255, 255, 255, 0.6);
}
@keyframes flipCoin {
0% { transform: rotateY(0deg); }
100% { transform: rotateY(2160deg); }
}
.neon-text {
text-shadow:
0 0 10px var(--gen-green),
0 0 20px var(--gen-green),
0 0 40px var(--gen-green);
}
.result-win {
animation: popIn 0.6s ease;
}
@keyframes popIn {
0% { transform: scale(0.8); opacity: 0; }
50% { transform: scale(1.15); }
100% { transform: scale(1); }
}
.particle {
position: absolute;
pointer-events: none;
animation: particleFloat 2s ease forwards;
}
</style>
πͺ
GenFlip
LIVE ON GENLAYER
<!-- Right side -->
<div class="flex items-center gap-x-8">
<!-- Wallet -->
<button onclick="connectWallet()" id="wallet-btn"
class="flex items-center gap-x-2 bg-white/5 hover:bg-white/10 border border-white/10 hover:border-white/30 px-6 py-3 rounded-3xl font-medium text-sm">
<i class="fa-solid fa-wallet"></i>
<span id="wallet-address" class="font-mono">Connect GenLayer Wallet</span>
</button>
<!-- Balance -->
<div class="flex items-center gap-x-3 bg-white/5 border border-white/10 rounded-3xl px-5 py-3">
<i class="fa-solid fa-coins text-amber-400"></i>
<div>
<span id="balance" class="font-mono text-xl font-semibold">1,337.42</span>
<span class="text-xs text-emerald-400 ml-1">GLT</span>
</div>
</div>
<a href="https://www.genlayer.com" target="_blank"
class="flex items-center gap-x-2 text-sm font-medium hover:text-emerald-400">
<span>Powered by</span>
<span class="font-semibold text-emerald-400">GenLayer</span>
<i class="fa-solid fa-arrow-up-right-from-square text-xs"></i>
</a>
</div>
</div>
</nav>
<div class="max-w-7xl mx-auto px-6 py-12">
<!-- Hero Header -->
<div class="text-center mb-12">
<div class="inline-flex items-center gap-x-2 bg-white/10 text-emerald-400 text-sm font-medium px-6 py-2 rounded-3xl mb-6 border border-emerald-400/30">
<i class="fa-solid fa-robot"></i>
AI-VERIFIED β’ INTELLIGENT CONTRACTS β’ 100% ON-CHAIN
</div>
<h1 class="title-font text-7xl md:text-8xl font-bold tracking-tighter neon-text leading-none mb-4">
HEADS<span class="text-emerald-400">.</span> OR<span class="text-emerald-400">.</span> TAILS
</h1>
<p class="text-2xl text-white/70 max-w-md mx-auto">
The most beautiful coin flip on GenLayer.<br>
Fair. Instant. AI-powered.
</p>
<div class="flex justify-center gap-8 mt-8 text-sm">
<div class="flex items-center gap-2">
<i class="fa-solid fa-shield-halved text-emerald-400"></i>
<span>Provably Fair</span>
</div>
<div class="flex items-center gap-2">
<i class="fa-solid fa-bolt text-amber-400"></i>
<span>Instant Settlement</span>
</div>
<div class="flex items-center gap-2">
<i class="fa-solid fa-brain text-purple-400"></i>
<span>Intelligent Randomness</span>
</div>
</div>
</div>
<div class="grid lg:grid-cols-12 gap-8">
<!-- Game Panel -->
<div class="lg:col-span-7 bg-white/5 backdrop-blur-2xl border border-white/10 rounded-3xl p-8 shadow-2xl">
<!-- Choice Selection -->
<div class="flex justify-center gap-8 mb-10">
<!-- Heads -->
<button onclick="selectSide('heads')" id="heads-btn"
class="group flex-1 max-w-[220px] bg-gradient-to-br from-amber-400 to-yellow-500 text-black rounded-3xl p-6 hover:scale-105 active:scale-95 flex flex-col items-center border-4 border-transparent hover:border-amber-300">
<div class="text-7xl mb-3">πͺ</div>
<div class="text-4xl font-bold title-font tracking-tighter">HEADS</div>
<div class="text-xs font-mono uppercase mt-2 opacity-75">50% chance β’ 2x payout</div>
</button>
<!-- Tails -->
<button onclick="selectSide('tails')" id="tails-btn"
class="group flex-1 max-w-[220px] bg-gradient-to-br from-slate-300 to-slate-100 text-black rounded-3xl p-6 hover:scale-105 active:scale-95 flex flex-col items-center border-4 border-transparent hover:border-slate-400">
<div class="text-7xl mb-3">πͺ</div>
<div class="text-4xl font-bold title-font tracking-tighter">TAILS</div>
<div class="text-xs font-mono uppercase mt-2 opacity-75">50% chance β’ 2x payout</div>
</button>
</div>
<!-- The Coin -->
<div class="flex flex-col items-center mb-10">
<div id="coin-container" class="coin-container">
<div id="coin" class="coin" onclick="if(!isFlipping) flipCoin()">
<!-- Heads Face -->
<div class="coin-face coin-heads">
<span class="coin-label">H</span>
</div>
<!-- Tails Face -->
<div class="coin-face coin-tails">
<span class="coin-label">T</span>
</div>
</div>
</div>
<div class="text-center mt-6">
<button onclick="flipCoin()" id="flip-button"
class="disabled:opacity-50 disabled:cursor-not-allowed bg-emerald-500 hover:bg-emerald-600 text-black font-semibold text-2xl px-16 py-6 rounded-3xl flex items-center gap-x-3 mx-auto shadow-[0_0_40px_-10px] shadow-emerald-500">
<i class="fa-solid fa-arrow-rotate-right"></i>
<span id="flip-text">FLIP THE COIN</span>
</button>
<p id="status-text" class="text-white/60 text-sm mt-4 font-mono">Select Heads or Tails β’ Click coin or button to flip</p>
</div>
</div>
<!-- Result -->
<div id="result-panel" class="hidden bg-black/30 border border-white/10 rounded-3xl p-6 text-center">
<div id="result-icon" class="text-8xl mb-4"></div>
<h3 id="result-title" class="text-5xl title-font font-bold mb-1"></h3>
<p id="result-subtitle" class="text-xl text-white/70"></p>
<div class="mt-6 flex justify-center gap-8 text-sm font-mono">
<div class="text-center">
<div class="text-emerald-400">YOU BET</div>
<div id="bet-display" class="text-3xl font-bold"></div>
</div>
<div class="text-center">
<div class="text-white/60">RESULT</div>
<div id="result-display" class="text-3xl font-bold"></div>
</div>
<div class="text-center">
<div class="text-emerald-400">PAYOUT</div>
<div id="payout-display" class="text-3xl font-bold text-emerald-400"></div>
</div>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="lg:col-span-5 space-y-6">
<!-- Stats -->
<div class="bg-white/5 backdrop-blur-2xl border border-white/10 rounded-3xl p-6">
<div class="flex justify-between items-baseline mb-6">
<h3 class="text-lg font-semibold">Live Stats</h3>
<div class="text-xs font-mono text-emerald-400">ON GENLAYER MAINNET</div>
</div>
<div class="grid grid-cols-3 gap-4">
<div class="text-center bg-black/30 rounded-2xl py-4">
<div class="text-4xl font-bold text-emerald-400" id="total-flips">248,419</div>
<div class="text-xs font-mono uppercase">Flips Today</div>
</div>
<div class="text-center bg-black/30 rounded-2xl py-4">
<div class="text-4xl font-bold text-amber-400" id="biggest-win">42.8 GLT</div>
<div class="text-xs font-mono uppercase">Biggest Win</div>
</div>
<div class="text-center bg-black/30 rounded-2xl py-4">
<div class="text-4xl font-bold" id="win-rate">49.8%</div>
<div class="text-xs font-mono uppercase">Heads Win Rate</div>
</div>
</div>
</div>
<!-- Flip History -->
<div class="bg-white/5 backdrop-blur-2xl border border-white/10 rounded-3xl p-6 flex-1 flex flex-col">
<h3 class="text-lg font-semibold mb-4 flex items-center justify-between">
Recent Flips
<span onclick="clearHistory()" class="text-xs cursor-pointer hover:text-red-400">CLEAR</span>
</h3>
<div id="history-list" class="flex-1 overflow-auto space-y-3 text-sm font-mono">
<!-- Populated by JS -->
</div>
</div>
<!-- How it works -->
<div class="text-xs bg-white/5 border border-white/10 rounded-3xl p-6 leading-relaxed">
<div class="flex gap-2 items-center mb-3 text-emerald-400">
<i class="fa-solid fa-circle-info"></i>
<strong>Powered by GenLayer Intelligent Contracts</strong>
</div>
<p class="opacity-75">
Your flip is executed by an AI-augmented Python contract on GenLayer.
True randomness is verified by multiple LLM validators.
No oracles. No trust. Pure decentralized beauty.
</p>
<a href="https://docs.genlayer.com" target="_blank"
class="inline-flex items-center gap-1 text-emerald-400 text-xs mt-4 hover:underline">
View contract source on GenLayer Studio β
</a>
</div>
</div>
</div>
</div>
<!-- Footer bar -->
<div class="bg-black/70 border-t border-white/10 py-4 text-center text-xs font-mono text-white/40">
Built as a beautiful demo dApp for GenLayer β’ Intelligent Contracts in Python β’ Try it on GenLayer Testnet
</div>
<script>
// Tailwind script already loaded
function initializeTailwind() {
// Already initialized via CDN
}
// Game state
let selectedSide = null
let isFlipping = false
let balance = 1337.42
let history = []
// Fake GenLayer wallet
let walletConnected = false
let walletAddress = "0x7aF8...9kL2"
function connectWallet() {
const btn = document.getElementById('wallet-btn')
if (!walletConnected) {
// Simulate GenLayer wallet connection
btn.innerHTML = `
<i class="fa-solid fa-circle-check text-emerald-400"></i>
<span class="font-mono">${walletAddress}</span>
`
walletConnected = true
createConfetti()
showToast("β
Connected to GenLayer Wallet", "Now flipping with real on-chain randomness!")
} else {
alert("Already connected! (Demo)")
}
}
function selectSide(side) {
if (isFlipping) return
selectedSide = side
// Reset buttons
document.getElementById('heads-btn').classList.remove('ring-4', 'ring-offset-4', 'ring-emerald-400')
document.getElementById('tails-btn').classList.remove('ring-4', 'ring-offset-4', 'ring-emerald-400')
// Highlight chosen
const chosenBtn = document.getElementById(side + '-btn')
chosenBtn.classList.add('ring-4', 'ring-offset-4', 'ring-emerald-400')
document.getElementById('flip-text').textContent = `FLIP FOR ${side.toUpperCase()}`
document.getElementById('status-text').innerHTML = `You chose <span class="text-emerald-400 uppercase">${side}</span> β’ Ready to flip`
}
function flipCoin() {
if (isFlipping || !selectedSide) {
if (!selectedSide) showToast("β οΈ First choose Heads or Tails!", "Pick a side above")
return
}
isFlipping = true
const coin = document.getElementById('coin')
const status = document.getElementById('status-text')
// Start flipping animation
coin.classList.add('flipping')
status.textContent = 'FLIPPING ON GENLAYER... AI validators confirming fairness'
// Disable button
const flipBtn = document.getElementById('flip-button')
flipBtn.disabled = true
// Simulate on-chain delay + animation
setTimeout(() => {
// Determine result
const result = Math.random() > 0.5 ? 'heads' : 'tails'
// Reset animation
coin.classList.remove('flipping')
// Force final rotation based on result
if (result === 'tails') {
coin.style.transform = 'rotateY(1800deg)'
} else {
coin.style.transform = 'rotateY(1980deg)'
}
// Show result after small delay
setTimeout(() => {
handleResult(result)
}, 600)
}, 3200)
}
function handleResult(result) {
isFlipping = false
const coin = document.getElementById('coin')
// Reset coin visual
setTimeout(() => {
coin.style.transform = result === 'tails' ? 'rotateY(180deg)' : 'rotateY(0deg)'
}, 100)
// Calculate win
const win = result === selectedSide
let payout = win ? 20 : -10 // Fake 2x bet of 10 GLT
// Update balance
balance += payout
document.getElementById('balance').textContent = balance.toFixed(2)
// Show result panel
const panel = document.getElementById('result-panel')
panel.classList.remove('hidden')
panel.classList.add('result-win')
const iconEl = document.getElementById('result-icon')
const titleEl = document.getElementById('result-title')
const subtitleEl = document.getElementById('result-subtitle')
const betEl = document.getElementById('bet-display')
const resultEl = document.getElementByI