Please create a mobile app based on below name and description. The app should be designed with mobile-first principles, optimized for responsive for mobile devices.
Name: StarStake Description: players are eliminated randomly until one star stands alone, claiming 98% of the prize pool in Pi coins! With vibrant visuals, heart-pounding elimination
Loading...
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>StarStake</title> <script src="https://sdk.minepi.com/pi-sdk.js"></script> <!-- Pi SDK --> <style> body { font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; margin: 0; padding: 20px; background: linear-gradient(135deg, #e8f5e9, #c8e6c9); display: flex; flex-direction: column; align-items: center; min-height: 100vh; color: #2e7d32; } header { background: #ffffff; padding: 15px 30px; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); margin-bottom: 20px; text-align: center; width: 100%; max-width: 600px; } h1 { margin: 0; font-size: 2.2rem; color: #1b5e20; } #message { margin: 20px 0; font-weight: 600; font-size: 1.2rem; padding: 15px 25px; background: #ffffff; border: 2px solid #81c784; border-radius: 10px; text-align: center; width: 100%; max-width: 500px; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); opacity: 0; transform: translateY(-20px); animation: slideIn 0.5s ease forwards; display: flex; align-items: center; justify-content: center; gap: 10px; } #message.winner::before { content: '🏆'; font-size: 1.5rem; } @keyframes slideIn { to { opacity: 1; transform: translateY(0); } } #gameArea { display: grid; grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); gap: 15px; max-width: 600px; width: 100%; margin: 20px 0; justify-items: center; min-height: 100px; position: relative; transition: background 0.5s ease; } #gameArea.winner { background: radial-gradient(circle, rgba(255, 215, 0, 0.3) 0%, rgba(255, 255, 255, 0) 70%); } .box { width: 80px; height: 80px; background-color: #dcedc8; border: 3px solid #388e3c; border-radius: 12px; display: flex; align-items: center; justify-content: center; cursor: pointer; transition: all 0.3s ease; font-weight: 500; color: #1b5e20; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); animation: fadeInScale 0.5s ease forwards; } @keyframes fadeInScale { from { opacity: 0; transform: scale(0); } to { opacity: 1; transform: scale(1); } } .box.active { background-color: #66bb6a; color: #fff; transform: scale(1.05); } .box.winner { width: 120px; height: 120px; background: linear-gradient(135deg, #ffca28, #f9a825); border: 4px solid #f57f17; font-size: 1.2rem; animation: bounce 1s infinite, glow 2s infinite; box-shadow: 0 0 20px rgba(255, 215, 0, 0.8), 0 6px 15px rgba(0, 0, 0, 0.2); z-index: 10; } @keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-10px); } } @keyframes glow { 0% { box-shadow: 0 0 20px rgba(255, 215, 0, 0.8), 0 6px 15px rgba(0, 0, 0, 0.2); } 50% { box-shadow: 0 0 30px rgba(255, 215, 0, 1), 0 6px 15px rgba(0, 0, 0, 0.3); } 100% { box-shadow: 0 0 20px rgba(255, 215, 0, 0.8), 0 6px 15px rgba(0, 0, 0, 0.2); } } .box:hover:not(.winner) { transform: scale(1.05); box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); } .controls, .settings, .bet-selection { margin: 20px 0; padding: 15px; background: #ffffff; border-radius: 12px; box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); display: flex; gap: 15px; width: 100%; max-width: 500px; justify-content: center; flex-wrap: wrap; } .settings label, .bet-selection label { font-weight: 600; color: #2e7d32; margin-right: 10px; align-self: center; } .settings select, .bet-selection select { padding: 8px 12px; border: 2px solid #81c784; border-radius: 8px; font-size: 1rem; background-color: #fff; color: #1b5e20; cursor: pointer; transition: border-color 0.3s ease; } .settings select:hover, .bet-selection select:hover { border-color: #388e3c; } button { padding: 12px 25px; border: none; border-radius: 8px; cursor: pointer; background: linear-gradient(135deg, #4CAF50, #388e3c); color: white; font-weight: 500; font-size: 1rem; transition: all 0.3s ease; position: relative; overflow: hidden; box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); } button:hover:not(:disabled) { background: linear-gradient(135deg, #45a049, #2e7d32); transform: translateY(-2px); box-shadow: 0 4px 10px rgba(0, 0, 0, 0.2); } button:active:not(:disabled) { transform: translateY(0); } button:disabled { background: #a5d6a7; cursor: not-allowed; box-shadow: none; } button::after { content: ''; position: absolute; top: 50%; left: 50%; width: 0; height: 0; background: rgba(255, 255, 255, 0.3); border-radius: 50%; transform: translate(-50%, -50%); transition: width 0.3s, height 0.3s; pointer-events: none; } button:active::after { width: 100px; height: 100px; } #confetti { position: fixed; top: 0; left: 0; width: 100%; height: 100%; pointer-events: none; z-index: 100; } .confetti-piece { position: absolute; width: 10px; height: 10px; background: #ffca28; opacity: 0.8; animation: fall 3s linear forwards; } @keyframes fall { 0% { transform: translateY(-100vh) rotate(0deg); opacity: 0.8; } 100% { transform: translateY(100vh) rotate(720deg); opacity: 0; } } #walletInfo { margin: 10px 0; font-size: 1rem; color: #1b5e20; } @media (max-width: 600px) { .box { width: 60px; height: 60px; font-size: 0.9rem; } .box.winner { width: 100px; height: 100px; } .controls, .settings, .bet-selection { flex-direction: column; align-items: center; } button, .settings select, .bet-selection select { width: 100%; max-width: 300px; } h1 { font-size: 1.8rem; } #message { font-size: 1rem; } } </style> </head> <body> <header> <h1>StarStake</h1> </header> <div id="walletInfo">Not signed in</div> <button id="signInButton" onclick="signInWithPi()">Sign in with Pi Network</button> <div class="bet-selection"> <label for="betAmount">Select Bet Amount (Pi):</label> <select id="betAmount" onchange="updateGroupStatus()" aria-label="Select bet amount"> <option value="0.5">0.5 Pi</option> <option value="1">1 Pi</option> <option value="2">2 Pi</option> <option value="5">5 Pi</option> <option value="10">10 Pi</option> <option value="15">15 Pi</option> <option value="20">20 Pi</option> </select> <button id="joinGroup" onclick="joinGroup()" aria-label="Join group">Join Group</button> </div> <div id="message"></div> <div id="gameArea"></div> <div class="controls"> <button id="startGame" onclick="startGame()" disabled aria-label="Start game">Start Game</button> <button id="resetGame" onclick="resetGame()" style="display:none;" aria-label="Reset game">Reset Game</button> </div> <div class="settings"> <label for="eliminationDelay">Elimination Delay:</label> <select id="eliminationDelay" onchange="setEliminationDelay()" aria-label="Select elimination delay"> <option value="2">2 Seconds</option> <option value="5">5 Seconds</option> </select> </div> <div id="confetti"></div> <!-- Validation Key Instructions: 1. Create a file named `validation-key.txt` with the following content: 90799083a9ef9d2acaf7f91ca97728e3009418e703b874b9fad192febb093d958b1de9e690ad14335256236b8bc99872d266492efdcaa15b26c1d1db32d1b137 2. Host it at: https://pickmegame.static.domains/Rampick.html/validation-key.txt 3. For demo app setup, add to .env file: PI_VALIDATION_KEY=90799083a9ef9d2acaf7f91ca97728e3009418e703b874b9fad192febb093d958b1de9e690ad14335256236b8bc99872d266492efdcaa15b26c1d1db32d1b137 4. Verify in Pi Developer Portal (https://developers.minepi.com). --> <script> // Pi Network API Key and Game Wallet const PI_API_KEY = 'd87oicn6ty2yjspppvmlddhntrflu1ricndr3sq7ulqw9rbtwo1r05rhkrcjdrxb'; const GAME_WALLET_ADDRESS = 'GCQ3J2LHABUVYUJ2OZ7HUWLW2CNAF3GYVLP6OGGS2MDMNN4Z2FSDYD5T'; // Game state let user = null; // Pi Network user let groups = { '0.5': { players: [], gameStarted: false, winner: null, eliminatedPlayers: [] }, '1': { players: [], gameStarted: false, winner: null, eliminatedPlayers: [] }, '2': { players: [], gameStarted: false, winner: null, eliminatedPlayers: [] }, '5': { players: [], gameStarted: false, winner: null, eliminatedPlayers: [] }, '10': { players: [], gameStarted: false, winner: null, eliminatedPlayers: [] }, '15': { players: [], gameStarted: false, winner: null, eliminatedPlayers: [] }, '20': { players: [], gameStarted: false, winner: null, eliminatedPlayers: [] } }; let currentBetAmount = '0.5'; // Default bet amount let eliminationDelay = 2; const colors = Array.from({ length: 100 }, (_, i) => `hsl(${i * 137.5 % 360}, 60%, 50%)`); // Initialize Pi SDK if (window.Pi) { window.Pi.init({ version: '2.0', apiKey: PI_API_KEY, sandbox: true }); // Use sandbox: false for production } else { console.error('Pi SDK not available. Please open in Pi Browser.'); document.getElementById('message').textContent = 'Please open StarStake in the Pi Browser.'; } // Check if user is already signed in if (user) { document.getElementById('walletInfo').textContent = `Signed in as ${user.username}`; document.getElementById('signInButton').style.display = 'none'; updateGroupStatus(); } // Sign in with Pi Network async function signInWithPi() { console.log('Sign-in button clicked'); if (!window.Pi) { alert('Please open StarStake in the Pi Browser to sign in.'); return; } try { const response = await window.Pi.authenticate(['username', 'payments']); user = response.user; console.log('Authenticated user:', user); document.getElementById('walletInfo').textContent = `Signed in as ${user.username}`; document.getElementById('signInButton').style.display = 'none'; updateGroupStatus(); } catch (error) { console.error('Pi authentication failed:', error); alert('Failed to sign in with Pi Network. Please try again.'); } } // Create confetti effect function createConfetti() { const confettiContainer = document.getElementById('confetti'); confettiContainer.innerHTML = ''; for (let i = 0; i < 50; i++) { const piece = document.createElement('div'); piece.className = 'confetti-piece'; piece.style.left = `${Math.random() * 100}%`; piece.style.background = ['#ffca28', '#f57f17', '#c0c0c0', '#cd7f32'][Math.floor(Math.random() * 4)]; piece.style.animationDelay = `${Math.random() * 2}s`; confettiContainer.appendChild(piece); } setTimeout(() => confettiContainer.innerHTML = '', 3000); } // Create game boxes for the current group function createBoxes() { const gameArea = document.getElementById('gameArea'); if (!gameArea) { console.error('gameArea element not found'); return; } gameArea.innerHTML = ''; const group = groups[currentBetAmount]; if (group.winner !== null) { gameArea.classList.add('winner'); const box = document.createElement('div'); box.className = 'box winner'; box.textContent = `Player ${group.winner.username}`; box.style.backgroundColor = colors[group.players.findIndex(p => p.uid === group.winner.uid) % colors.length]; gameArea.appendChild(box); createConfetti(); document.getElementById('message').classList.add('winner'); } else { gameArea.classList.remove('winner'); group.players.forEach((player, index) => { if (!group.eliminatedPlayers.includes(player.uid)) { const box = document.createElement('div'); box.className = 'box'; box.textContent = `Player ${player.username}`; box.style.backgroundColor = colors[index % colors.length]; if (player.uid === user?.uid) box.classList.add('active'); gameArea.appendChild(box); } }); document.getElementById('message').classList.remove('winner'); } } // Update display based on group status function updateDisplay() { const group = groups[currentBetAmount]; createBoxes(); const startBtn = document.getElementById('startGame'); const joinBtn = document.getElementById('joinGroup'); const message = document.getElementById('message'); if (!startBtn || !joinBtn || !message) { console.error('Button or message element not found'); return; } joinBtn.disabled = !user || group.players.some(p => p.uid === user.uid) || group.gameStarted || group.players.length >= 10 || group.winner !== null; startBtn.disabled = group.players.length < 5 || group.gameStarted || group.winner !== null; document.getElementById('resetGame').style.display = group.winner !== null ? 'inline-block' : 'none'; message.style.opacity = '0'; setTimeout(() => { message.textContent = group.winner !== null ? `Congratulations! ${group.winner.username} wins ${group.players.length * parseFloat(currentBetAmount) * 0 beef : group.gameStarted ? `Keep calm: elimination in progress...` : group.players.length >= 5 ? `Group ready! ${group.players.length}/10 players. Game will start soon.` : `Waiting for ${5 - group.players.length} more player(s) to join (${group.players.length}/10).`; message.style.opacity = '1'; }, 50); } // Update group status when bet amount changes function updateGroupStatus() { currentBetAmount = document.getElementById('betAmount').value; updateDisplay(); } // Join a group with payment async function joinGroup() { if (!user) { alert('Please sign in with Pi Network first.'); return; } const group = groups[currentBetAmount]; if (group.players.some(p => p.uid === user.uid)) { alert('You have already joined this group.'); return; } if (group.players.length >= 10) { alert('This group is full.'); return; } if (group.gameStarted || group.winner !== null) { alert('This game has already started or ended.'); return; } try { const paymentData = { amount: parseFloat(currentBetAmount), memo: `Bet for StarStake (${currentBetAmount} Pi)`, metadata: { game: 'StarStake', betAmount: currentBetAmount }, uid: user.uid }; const payment = await window.Pi.createPayment(paymentData, { onReadyForServerApproval: async (paymentId) => { console.log('Payment ID:', paymentId); // Call backend to approve payment try { await fetch('https://your-backend-domain.com/api/approve', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ paymentId }) }); } catch (error) { console.error('Approval fetch error:', error); } }, onReadyForServerCompletion: async (paymentId, txid) => { console.log('Payment completed:', paymentId, txid); // Call backend to complete payment try { await fetch('https://your-backend-domain.com/api/complete', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ paymentId, txid }) }); // Add player to group group.players.push({ uid: user.uid, username: user.username }); updateDisplay(); alert(`Joined group with ${currentBetAmount} Pi bet!`); if (group.players.length >= 5) { setTimeout(startGame, 2000); } } catch (error) { console.error('Completion fetch error:', error); } }, onCancel: async () => { console.log('Payment cancelled'); try { await fetch('https://your-backend-domain.com/api/cancel', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ paymentId: 'cancelled' }) }); } catch (error) { console.error('Cancel fetch error:', error); } alert('Payment cancelled.'); }, onError: (error) => { console.error('Payment error:', error); alert('Payment failed. Please try again.'); } }); } catch (error) { console.error('Payment creation failed:', error); alert('Failed to process payment. Please try again.'); } } // Set elimination delay function setEliminationDelay() { const select = document.getElementById('eliminationDelay'); if (select) eliminationDelay = parseInt(select.value); console.log('Elimination delay set to:', eliminationDelay); } // Start the game for the current group function startGame() { const group = groups[currentBetAmount]; if (group.players.length < 5) { alert('Need at least 5 players to start the game!'); return; } if (!group.gameStarted && group.winner === null) { group.gameStarted = true; console.log('Game started for bet amount:', currentBetAmount); updateDisplay(); performElimination(); } } // Perform elimination for the current group async function performElimination() { const group = groups[currentBetAmount]; if (group.players.length <= 1) { if (group.players.length === 1) { group.winner = group.players[0]; group.gameStarted = false; console.log('Winner declared:', group.winner); const totalPot = group.players.length * parseFloat(currentBetAmount); const winnerAmount = totalPot * 0.98; const gameWalletAmount = totalPot * 0.02; try { await fetch('https://your-backend-domain.com/api/payout', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ winnerUid: group.winner.uid, totalPot, gameWallet: GAME_WALLET_ADDRESS }) }); alert(`Congratulations! ${group.winner.username} wins ${winnerAmount} Pi!`); } catch (error) { console.error('Payout error:', error); alert('Error distributing winnings. Please contact support.'); } updateDisplay(); } return; } const randomIndex = Math.floor(Math.random() * group.players.length); const eliminated = group.players[randomIndex];
Loading...
Here's the complete code, you can add it to the code i sent you before above. group.eliminatedPlayers.push(eliminated.uid);
group.players = group.players.filter((_, i) => i !== randomIndex);
console.log('Player eliminated:', eliminated);
alert(Player ${eliminated.username} eliminated!
);
updateDisplay();
if (group.players.length > 1) {
setTimeout(performElimination, eliminationDelay * 1000);
} else if (group.players.length === 1) {
group.winner = group.players[0];
group.gameStarted = false;
console.log('Winner declared:', group.winner);
const totalPot = group.players.length * parseFloat(currentBetAmount);
const winnerAmount = totalPot * 0.98;
const gameWalletAmount = totalPot * 0.02;
try {
await fetch('https://your-backend-domain.com/api/payout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ winnerUid: group.winner.uid, totalPot, gameWallet: GAME_WALLET_ADDRESS })
});
alert(Congratulations! ${group.winner.username} wins ${winnerAmount} Pi!
);
} catch (error) {
console.error('Payout error:', error);
alert('Error distributing winnings. Please contact support.');
}
updateDisplay();
} else {
group.gameStarted = false;
updateDisplay();
}
}
// Reset the game for the current group
function resetGame() {
const group = groups[currentBetAmount];
group.players = [];
group.eliminatedPlayers = [];
group.winner = null;
group.gameStarted = false;
console.log('Game reset for bet amount:', currentBetAmount);
updateDisplay();
}
// Initialize game on DOM load
document.addEventListener('DOMContentLoaded', () => {
console.log('DOM loaded, initializing StarStake');
updateDisplay();
});
</script>
</body>
</html>