A Pen by Nathan Castellanos on CodePen.
Created
June 6, 2025 15:41
-
-
Save nathanncc/7bd23d157a1e8e19cf9e8b58fb13aa3e to your computer and use it in GitHub Desktop.
full screen js canvas template
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
}<!DOCTYPE html> | |
<html lang="en"> | |
<head> | |
<meta charset="UTF-8" /> | |
<title>JC Blackjack</title> | |
<link href="https://fonts.googleapis.com/css2?family=Great+Vibes&display=swap" rel="stylesheet"> | |
<link rel="stylesheet" href="style.css" /> | |
</head> | |
<body> | |
<div class="logo">JC</div> | |
<div id="betting-section" class="active"> | |
<h2>Place your bet</h2> | |
<div id="bankroll">Bankroll: $10000</div> | |
<div id="current-bet">Current Bet: $0</div> | |
<div class="chips"> | |
<button class="chip" data-value="100">$100</button> | |
<button class="chip" data-value="500">$500</button> | |
<button class="chip" data-value="1000">$1000</button> | |
<button class="chip" data-value="10000">$10,000</button> | |
<button id="all-in-btn" class="chip" style="background-color:#ffd700; color:#1B2B38;">All In</button> | |
</div> | |
<div class="bet-buttons"> | |
<button id="place-bet-btn">Place Bet & Start Game</button> | |
<button id="clear-bet-btn">Clear Bet</button> | |
</div> | |
<div id="message"></div> | |
</div> | |
<div id="game-section" style="display:none;"> | |
<h2>Blackjack</h2> | |
<div> | |
<h3>Dealer</h3> | |
<div id="dealer-cards" class="cards"></div> | |
<div id="dealer-score"></div> | |
</div> | |
<div> | |
<h3>Player</h3> | |
<div id="player-cards" class="cards"></div> | |
<div id="player-score"></div> | |
</div> | |
<button id="hit-btn">Hit</button> | |
<button id="stand-btn">Stand</button> | |
<button id="new-game-btn">Quit Game</button> | |
<div id="message"></div> | |
</div> | |
<script src="script.js"></script> | |
<div class="logo">JC</div> | |
</body> | |
</html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
let deck = []; | |
let dealerCards = []; | |
let playerCards = []; | |
let gameOver = false; | |
let bankroll = 10000; | |
let currentBet = 0; | |
let gameActive = false; | |
const dealerCardsEl = document.getElementById('dealer-cards'); | |
const playerCardsEl = document.getElementById('player-cards'); | |
const dealerScoreEl = document.getElementById('dealer-score'); | |
const playerScoreEl = document.getElementById('player-score'); | |
const messageEl = document.querySelectorAll('#message')[0]; | |
const messageElGame = document.querySelectorAll('#message')[1]; | |
const hitBtn = document.getElementById('hit-btn'); | |
const standBtn = document.getElementById('stand-btn'); | |
const newGameBtn = document.getElementById('new-game-btn'); | |
const bankrollEl = document.getElementById('bankroll'); | |
const currentBetEl = document.getElementById('current-bet'); | |
const chips = document.querySelectorAll('.chip'); | |
const placeBetBtn = document.getElementById('place-bet-btn'); | |
const clearBetBtn = document.getElementById('clear-bet-btn'); | |
const bettingSection = document.getElementById('betting-section'); | |
const gameSection = document.getElementById('game-section'); | |
const allInBtn = document.getElementById('all-in-btn'); | |
const gamblerQuotes = [ | |
"99% of gamblers quit before their biggest win...", | |
"Double or nothing always wins eventually!", | |
"If you're losing, just bet more!", | |
"The next hand is the one...", | |
"You can't lose forever — statistically speaking.", | |
"Debt is temporary. Winning is forever." | |
]; | |
const memeImages = [ | |
"/mnt/data/99e04009-fa92-4ff1-8259-9f174fed75db.png", | |
"/mnt/data/39dc400f-2c94-4236-b7ef-b4ce3ffd5599.png", | |
"/mnt/data/65c63896-cae1-493b-a59f-a14812782e69.png" | |
]; | |
hitBtn.addEventListener('click', hit); | |
standBtn.addEventListener('click', stand); | |
newGameBtn.addEventListener('click', endGame); | |
placeBetBtn.addEventListener('click', startGame); | |
clearBetBtn.addEventListener('click', clearBet); | |
chips.forEach(chip => { | |
chip.addEventListener('click', () => { | |
const amount = parseInt(chip.dataset.value); | |
if (!isNaN(amount)) { | |
addToBet(amount); | |
} | |
}); | |
}); | |
if (allInBtn) { | |
allInBtn.addEventListener('click', () => { | |
if (gameActive) { | |
messageEl.textContent = "Finish this hand first."; | |
return; | |
} | |
if (bankroll <= 0) { | |
messageEl.textContent = "You're broke!"; | |
return; | |
} | |
currentBet += bankroll; | |
bankroll = 0; | |
updateBankroll(); | |
updateCurrentBet(); | |
messageEl.textContent = 'All in!'; | |
}); | |
} | |
updateBankroll(); | |
updateCurrentBet(); | |
function addToBet(amount) { | |
if (gameActive || bankroll < amount) return; | |
currentBet += amount; | |
bankroll -= amount; | |
updateBankroll(); | |
updateCurrentBet(); | |
messageEl.textContent = ''; | |
} | |
function clearBet() { | |
if (gameActive) return; | |
bankroll += currentBet; | |
currentBet = 0; | |
updateBankroll(); | |
updateCurrentBet(); | |
messageEl.textContent = ''; | |
} | |
function updateBankroll() { | |
bankrollEl.textContent = `Bankroll: $${bankroll.toLocaleString()}`; | |
} | |
function updateCurrentBet() { | |
currentBetEl.textContent = `Current Bet: $${currentBet.toLocaleString()}`; | |
} | |
function createDeck() { | |
const suits = ['♥', '♦', '♣', '♠']; | |
const values = ['A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K']; | |
const deck = []; | |
for (let suit of suits) { | |
for (let value of values) { | |
deck.push({ suit, value }); | |
} | |
} | |
return deck; | |
} | |
function shuffleDeck(deck) { | |
for (let i = deck.length - 1; i > 0; i--) { | |
const j = Math.floor(Math.random() * (i + 1)); | |
[deck[i], deck[j]] = [deck[j], deck[i]]; | |
} | |
} | |
function drawCard() { | |
return deck.pop(); | |
} | |
function calculateScore(cards) { | |
let score = 0; | |
let aceCount = 0; | |
for (let card of cards) { | |
if (card.value === 'A') { | |
score += 11; | |
aceCount++; | |
} else if (['K', 'Q', 'J'].includes(card.value)) { | |
score += 10; | |
} else { | |
score += parseInt(card.value); | |
} | |
} | |
while (score > 21 && aceCount > 0) { | |
score -= 10; | |
aceCount--; | |
} | |
return score; | |
} | |
function startGame() { | |
if (currentBet <= 0) { | |
messageEl.textContent = "Please place a bet first!"; | |
return; | |
} | |
gameActive = true; | |
gameOver = false; | |
messageEl.textContent = ''; | |
messageElGame.textContent = ''; | |
dealerCards = []; | |
playerCards = []; | |
bettingSection.style.display = 'none'; | |
gameSection.style.display = 'block'; | |
deck = createDeck(); | |
shuffleDeck(deck); | |
dealerCards.push(drawCard()); | |
dealerCards.push(drawCard()); | |
playerCards.push(drawCard()); | |
playerCards.push(drawCard()); | |
updateGame(); | |
if (calculateScore(playerCards) === 21) { | |
setTimeout(() => stand(), 500); | |
} | |
} | |
function updateGame() { | |
dealerCardsEl.innerHTML = ''; | |
for (let i = 0; i < dealerCards.length; i++) { | |
if (i === 0 && !gameOver) { | |
dealerCardsEl.innerHTML += `<div class="card">?</div>`; | |
} else { | |
const card = dealerCards[i]; | |
dealerCardsEl.innerHTML += `<div class="card">${card.value}${card.suit}</div>`; | |
} | |
} | |
playerCardsEl.innerHTML = ''; | |
for (let card of playerCards) { | |
playerCardsEl.innerHTML += `<div class="card">${card.value}${card.suit}</div>`; | |
} | |
dealerScoreEl.textContent = gameOver ? `Score: ${calculateScore(dealerCards)}` : 'Score: ?'; | |
playerScoreEl.textContent = `Score: ${calculateScore(playerCards)}`; | |
hitBtn.disabled = gameOver; | |
standBtn.disabled = gameOver; | |
} | |
function hit() { | |
if (!gameOver) { | |
playerCards.push(drawCard()); | |
updateGame(); | |
if (calculateScore(playerCards) > 21) { | |
messageElGame.textContent = 'You busted! Dealer wins.'; | |
gameOver = true; | |
updateGame(); | |
setTimeout(endGame, 3000); | |
} | |
} | |
} | |
function stand() { | |
if (!gameOver) { | |
gameOver = true; | |
while (calculateScore(dealerCards) < 17) { | |
dealerCards.push(drawCard()); | |
} | |
updateGame(); | |
const dealerScore = calculateScore(dealerCards); | |
const playerScore = calculateScore(playerCards); | |
if (dealerScore > 21) { | |
messageElGame.textContent = 'Dealer busted! You win!'; | |
bankroll += currentBet * 2; | |
} else if (dealerScore > playerScore) { | |
messageElGame.textContent = 'Dealer wins!'; | |
} else if (playerScore > dealerScore) { | |
messageElGame.textContent = 'You win!'; | |
bankroll += currentBet * 2; | |
} else { | |
messageElGame.textContent = "It's a tie!"; | |
bankroll += currentBet; | |
} | |
updateBankroll(); | |
setTimeout(endGame, 4000); | |
} | |
} | |
function endGame() { | |
gameActive = false; | |
currentBet = 0; | |
updateCurrentBet(); | |
bettingSection.style.display = 'block'; | |
gameSection.style.display = 'none'; | |
const randomMeme = memeImages[Math.floor(Math.random() * memeImages.length)]; | |
const quote = gamblerQuotes[Math.floor(Math.random() * gamblerQuotes.length)]; | |
if (bankroll < -500) { | |
messageEl.innerHTML = ` | |
<div> | |
<img src="${randomMeme}" alt="Gambler Meme" style="max-width: 100%; height: auto; border-radius: 10px;"> | |
<p style="color: #e67e22; font-size: 18px; margin-top: 10px;">${quote}</p> | |
</div> | |
`; | |
} else if (bankroll < 0) { | |
messageEl.innerHTML = ` | |
<div> | |
<img src="${randomMeme}" alt="Gambler Meme" style="max-width: 100%; height: auto; border-radius: 10px;"> | |
<p style="color: #e67e22; font-size: 18px; margin-top: 10px;">99% of gamblers quit before their biggest win...</p> | |
</div> | |
`; | |
} else if (bankroll === 0) { | |
messageEl.textContent = "You're broke! Try to recover before going too deep!"; | |
} else { | |
messageEl.textContent = ''; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
body { | |
background-color: #1B2B38; | |
color: white; | |
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
margin: 0; | |
padding: 20px; | |
} | |
.logo { | |
font-family: 'Great Vibes', cursive; | |
font-size: 48px; | |
color: white; | |
position: fixed; | |
bottom: 20px; | |
right: 20px; | |
z-index: 999; | |
pointer-events: none; | |
} | |
#betting-section, | |
#game-section { | |
background-color: #1B2B38; | |
color: white; | |
padding: 20px; | |
border-radius: 10px; | |
max-width: 600px; | |
margin: 0 auto; | |
} | |
.chips { | |
margin-bottom: 15px; | |
} | |
.chip { | |
margin: 5px; | |
padding: 10px 15px; | |
font-weight: bold; | |
cursor: pointer; | |
background-color: transparent; | |
color: white; | |
border: 2px solid white; | |
border-radius: 8px; | |
transition: background-color 0.2s ease; | |
} | |
.chip:hover { | |
background-color: rgba(255, 255, 255, 0.1); | |
} | |
button { | |
margin: 5px 10px 15px 0; | |
padding: 10px 20px; | |
font-weight: bold; | |
cursor: pointer; | |
border-radius: 8px; | |
border: 2px solid white; | |
background-color: transparent; | |
color: white; | |
transition: background-color 0.2s ease; | |
} | |
button:hover { | |
background-color: rgba(255, 255, 255, 0.1); | |
} | |
.cards { | |
display: flex; | |
gap: 10px; | |
margin-bottom: 10px; | |
} | |
.card { | |
border: 1px solid white; | |
padding: 10px; | |
width: 40px; | |
height: 60px; | |
text-align: center; | |
font-size: 24px; | |
border-radius: 5px; | |
background-color: white; | |
color: #1B2B38; | |
user-select: none; | |
display: flex; | |
align-items: center; | |
justify-content: center; | |
} | |
#message { | |
margin-top: 15px; | |
font-weight: bold; | |
min-height: 22px; | |
color: white; | |
} | |
#message.win { | |
color: green; | |
} | |
#message.lose { | |
color: red; | |
} | |
#message.tie { | |
color: orange; | |
} | |
#bankroll, | |
#current-bet { | |
font-size: 18px; | |
margin-bottom: 10px; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment