Vibe Coding JavaScript Games First Chapters

Vibe Coding JavaScript Games
Build 15 Interactive Games While Mastering Real-World JavaScript, Game Logic, and AI-Assisted

https://github.com/lsvekis/Vibe-Coding-with-JavaScript-Book

https://lsvekis.github.io/Vibe-Coding-with-JavaScript-Book

What if you could learn JavaScript by building real games—and learn how to think like a developer at the same time?

Vibe Coding JavaScript Games is a hands-on, modern guide to learning JavaScript through the creation of 15 fully playable games, each designed to teach core programming concepts, real-world logic, and AI-assisted development techniques.

This isn’t just another “follow-the-steps” coding book.

It introduces a powerful new approach called Vibe Coding—a method that combines:

  • structured thinking
  • intentional prompting
  • iterative refinement
  • and real understanding of how code works

Instead of copying code, you’ll learn how to build systems, understand logic deeply, and use AI as a tool—not a shortcut.


🎮 What You’ll Build

Across 15 chapters, you’ll create progressively more advanced games, including:

  • 🎰 Slot Machine (state, randomness, game loops)
  • 🃏 Blackjack (turn-based logic, arrays, scoring systems)
  • 🎡 Roulette (probability, mapping logic to UI)
  • ♠️ Poker (hand evaluation, pattern detection)
  • 🦸 Hero Dice (combat systems, leveling, strategy)
  • 🚢 Trading & Exploration (dynamic economies, risk systems)
  • 🧠 And more advanced, original game systems

Each game introduces new concepts while reinforcing what you’ve already learned.


🧠 What You’ll Learn

This book goes beyond syntax. You’ll master:

  • how to design and manage game state
  • how to build logic-driven systems
  • how to connect UI to behavior
  • how to create random yet controlled outcomes
  • how to structure reusable functions and components
  • how to think in terms of systems, not just code

You’ll also learn how to use AI effectively:

  • writing better prompts
  • breaking problems into smaller parts
  • refining outputs instead of accepting them blindly
  • building faster while understanding more

⚡ The Vibe Learning System

Every chapter follows a proven learning framework:

  • Curiosity – Understand the problem
  • Build – Create a working version
  • Explain – Break down how it works
  • Refine – Improve using AI and logic
  • Extend – Add features and deepen understanding

This ensures you don’t just build projects—you retain and apply what you learn.


💡 Who This Book Is For

  • Beginners who want to learn JavaScript in a practical, engaging way
  • Developers who want to improve their logic and system design skills
  • Creators interested in AI-assisted coding workflows
  • Anyone who learns best by building real projects

🚀 What Makes This Book Different

Most coding books teach you what to type.

This book teaches you:

  • why it works
  • how to think
  • and how to build anything next

By the end of this book, you won’t just know JavaScript—you’ll know how to use it to create systems, games, and ideas from scratch.

Chapter 1 — Build Your First Game: Slot Machine Systems

Learning to Think Like a Game Developer with Vibe Coding


🔹 The Real Goal of This Chapter

You are not here to build a slot machine.

You are here to learn:

How to turn logic into an interactive system using JavaScript and AI-assisted thinking.

This chapter introduces the core architecture that every game in this book will use:

  • State → Logic → UI → Persistence → Loop

And you’ll learn how to use Vibe Coding to guide that process.


🔹 What Is Vibe Coding (In Practice)

Vibe Coding is not “just prompting AI.”

It’s a loop:

1. Intent

What are you trying to build?

2. Structure

What are the core parts?

3. Prompt

Ask AI for help with specific context

4. Evaluate

Does it behave correctly?

5. Refine

Improve logic, clarity, or UX


⚡ Rule
You are not generating code. You are shaping systems.


🔹 The System We’re Building

Your slot machine consists of:

ComponentResponsibility
StateStores all game data
Random EngineGenerates symbols
Game LogicDetermines wins/losses
UI RendererUpdates screen
Event SystemHandles clicks
PersistenceSaves progress

🔹 Step 1 — State (Single Source of Truth)

From your repo (script.js):

let state = {
bankroll: 500,
bet: 20,
reels: ["🍒", "🍋", "⭐"],
symbols: ["🍒", "🍋", "⭐", "💎", "7️⃣"],
history: []
};

🔍 Line-by-Line Breakdown

bankroll: 500

  • Player starts with 500 credits
  • This value changes every spin

bet: 20

  • Default bet amount
  • Used in payout calculations

reels: ["🍒", "🍋", "⭐"]

  • Represents current visible symbols
  • This is what the UI displays

symbols: [...]

  • All possible outcomes
  • The random system pulls from here

history: []

  • Stores previous spins
  • Enables features like:
    • recent results
    • analytics
    • UI history panels

🧠 Why This Structure Matters

Everything flows through this object.

If something breaks:
👉 You debug the state.


⚡ Vibe Insight
“If your state is clean, your game will be stable.”


🔹 Step 2 — Random Symbol Generator

function getRandomSymbol() {
const index = Math.floor(Math.random() * state.symbols.length);
return state.symbols[index];
}

🔍 Line-by-Line

Math.random()

  • Generates number between 0 and 1

* state.symbols.length

  • Scales it to array size

Math.floor(...)

  • Converts to integer index

🧠 What This Actually Means

You are mapping:

continuous randomness → discrete outcomes

🎯 Important Concept

This is where:

  • fairness
  • difficulty
  • probability

…are controlled.


⚡ Vibe Insight
“Randomness is a design decision — not an accident.”


🔹 Step 3 — Spin Logic (State Mutation)

function spinReels() {
state.reels = [
getRandomSymbol(),
getRandomSymbol(),
getRandomSymbol()
];
}

🔍 What Happens Here

  • Old reel values are replaced
  • New ones are generated instantly

🧠 Key Concept: Mutation

You are changing the game world.

That means:

  • UI must update
  • logic must re-run

⚡ Vibe Insight
“Every interaction = state change.”


🔹 Step 4 — Win Logic (Game Rules)

function checkWin() {
const [a, b, c] = state.reels; if (a === b && b === c) {
return state.bet * 5;
} return 0;
}

🔍 Line-by-Line

[a, b, c] = state.reels

  • destructures array for readability

a === b && b === c

  • checks for full match

return state.bet * 5

  • payout multiplier

🧠 Game Design Insight

This is your reward system.

Changing this changes:

  • difficulty
  • excitement
  • retention

⚡ Vibe Insight
“Rules define experience.”


🔹 Step 5 — Game Loop (Core Engine)

function playGame() {
spinReels(); const winnings = checkWin(); state.bankroll -= state.bet;
state.bankroll += winnings; state.history.unshift({
reels: [...state.reels],
win: winnings
}); render();
saveGame();
}

🔍 Line-by-Line

spinReels()

→ generate outcome


checkWin()

→ evaluate result


bankroll -= bet

→ cost of playing


bankroll += winnings

→ reward


history.unshift(...)

→ add to front of history


render()

→ update UI


saveGame()

→ persist state


🧠 Core Pattern

This is:

Input → Process → Output → Store

Every game in your repo uses this pattern.


🔹 Step 6 — UI Rendering

function render() {
document.getElementById("reel1").textContent = state.reels[0];
document.getElementById("reel2").textContent = state.reels[1];
document.getElementById("reel3").textContent = state.reels[2]; document.getElementById("bankroll").textContent = state.bankroll;
}

🧠 Important Concept

UI does NOT contain logic.

It only reflects state.


⚡ Vibe Insight
“If your UI breaks, your state is wrong — not your HTML.”


🔹 Step 7 — Persistence (localStorage)

function saveGame() {
localStorage.setItem("slotMachine", JSON.stringify(state));
}function loadGame() {
const saved = localStorage.getItem("slotMachine");
if (saved) {
state = JSON.parse(saved);
}
}

🔍 What This Does

  • converts state → string
  • stores it in browser
  • reloads on refresh

🧠 Why This Matters

Without this:

  • game resets every reload
  • no continuity

With this:

  • game feels real

⚡ Vibe Insight
“Memory creates meaning.”


🔹 Event Wiring (User Interaction)

document.getElementById("spinBtn")
.addEventListener("click", playGame);

🧠 What This Means

You are connecting:

  • UI → Logic

🔹 Vibe Coding — How You Actually Build This

Here’s how you should have built this with AI:


Prompt 1 — Structure First

“Create a JavaScript object to store slot machine state including bankroll, reels, symbols, and history.”


Prompt 2 — Random System

“Create a function that randomly selects items from an array and returns one value.”


Prompt 3 — Game Logic

“Write a function that checks if all elements in an array match and returns a payout.”


Prompt 4 — Game Loop

“Create a function that runs a full game cycle: spin reels, check win, update bankroll, and store results.”


Prompt 5 — UI Binding

“Update DOM elements based on a state object for a slot machine game.”


🔥 Why This Works

You are not asking AI to:
“build a game”

You are asking it to:

  • solve small systems
  • build pieces
  • connect logic

⚡ Vibe Insight
“Great developers don’t ask for solutions — they ask for components.”


🔹 Exercises (Advanced Learning)


🧪 Exercise 1 — Two Match Logic

Add:

if (a === b || b === c || a === c)

→ small win


🧪 Exercise 2 — Weighted Symbols

Make 💎 rare:

  • duplicate common symbols
  • reduce rare ones

🧪 Exercise 3 — Jackpot System

  • add state.jackpot
  • increase every spin
  • win on 777

🧪 Exercise 4 — Animation Layer

  • delay symbol reveal
  • simulate spinning

🧪 Exercise 5 — Loss Protection

  • track losing streak
  • increase payout chance

🔹 Reflection (Vibe Learning)

Answer:

  1. Where does randomness enter the system?
  2. What controls player reward?
  3. What would break if state was removed?
  4. How would you expand this to 5 reels?

🔹 What You Actually Learned

You now understand:

  • state-driven systems
  • randomness control
  • game loops
  • UI synchronization
  • persistence
  • AI-assisted development workflows

⚡ Final Insight
“You didn’t build a slot machine.
You built your first game engine.”


🔜 Next Chapter

Blackjack Command

You’ll learn:

  • multi-step decisions
  • player vs dealer logic
  • state branching

Chapter 2 — Blackjack Command

Build a Turn-Based Card Game with State, Rules, and Decision Logic

In Chapter 1, you built a slot machine and learned one of the most important lessons in game development:

a game is state + rules + input + output

That idea continues here, but Blackjack introduces something new:

decision flow

A slot machine is mostly event-driven randomness.
Blackjack is different. The player makes choices. The game responds. The dealer follows rules. The game must evaluate outcomes at multiple stages.

That makes Blackjack one of the best early JavaScript games you can build, because it teaches you how to manage:

  • arrays of objects
  • multi-step game state
  • rule-based turns
  • score calculation
  • user actions that change future outcomes
  • branching logic

This is where you stop thinking only in terms of “features” and start thinking in terms of systems that evolve over time.


The Vibe Learning Focus for This Chapter

This chapter uses the Vibe Learning format:

Curiosity

How do real card games keep track of cards, scores, turns, and outcomes?

Build

Create a working Blackjack game with dealing, hit, stand, and dealer logic.

Explain

Break the code into systems so you understand what each part does and why it exists.

Refine

Use Vibe Coding prompts to improve logic, readability, feedback, and gameplay.

Extend

Add features that move the project from a simple demo toward a fuller game.


The Goal of This Chapter

You are not just building Blackjack.

You are learning how to build a turn-based rules engine.

That means learning how to model:

  • a deck
  • a hand
  • a score
  • a round
  • player decisions
  • dealer behavior
  • game outcomes

If you understand this chapter deeply, you will be much more prepared for later games like:

  • Poker Showdown
  • Hero Dice: Villain Crisis
  • any RPG combat system
  • any tactical turn-based game

What We Are Building

In the repo version of Blackjack Command, the player can:

  • place a bet
  • deal a new hand
  • hit to take another card
  • stand to end their turn
  • compare against the dealer
  • win, lose, or push
  • track chip balance over time

This game teaches real JavaScript architecture because it must coordinate:

  • card data
  • deck data
  • player hand
  • dealer hand
  • score logic
  • UI state
  • round state

System Overview

Before we look at code, let’s break the game into the main systems.

SystemResponsibility
Deck SystemCreates and shuffles cards
Hand SystemStores player and dealer cards
Value SystemCalculates Blackjack scores
Turn SystemControls whether the player or dealer acts
Outcome SystemDetermines win, loss, bust, or push
Bankroll SystemTracks chips and bets
Render SystemUpdates the UI

That’s the Vibe Coding mindset:

Do not think “page.”
Think “systems.”


Step 1 — Model the State

A Blackjack game needs more structure than a slot machine.

A typical setup in your project looks like this:

let deck = [];
let player = [];
let dealer = [];
let inRound = false;let state = {
chips: 300,
bet: 25
};

What Each Part Does

deck = []

This stores the remaining cards that have not been drawn yet.

player = []

This stores the player’s current hand.

dealer = []

This stores the dealer’s current hand.

inRound = false

This controls whether a hand is active.
It prevents things like:

  • dealing twice during a round
  • changing the bet mid-hand
  • hitting after the round is over

state = { chips, bet }

This stores persistent player economy data:

  • how many chips are available
  • what the current wager is

Why This Matters

In Chapter 1, the state was mostly one object.

Here, it is split between:

  • persistent round-independent state like chips and bet
  • temporary round state like deck, player hand, dealer hand

That is a more advanced design pattern.


Developer Insight

Not all game state belongs in one giant object.

Sometimes it is cleaner to separate:

  • long-term state
  • short-term round state
  • UI state

That makes debugging easier.


Vibe Coding Prompt: Structure the State

Use a prompt like this early:

Create the JavaScript state structure for a blackjack game. Include deck, player hand, dealer hand, a flag for whether a round is active, and persistent chip and bet values.

Why this prompt works:

  • it asks for structure, not full code
  • it helps AI focus on architecture
  • it gives you a clean starting point

Step 2 — Create the Deck

Blackjack needs a full card deck, so we need a function to generate one.

A typical version looks like this:

function makeDeck() {
const suits = ["♠", "♥", "♦", "♣"];
const values = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]; deck = []; for (const suit of suits) {
for (const value of values) {
deck.push({ value, suit });
}
} 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]];
}
}

Code Breakdown

const suits = [...]

Defines the four suits in a standard deck.

const values = [...]

Defines all card ranks.

deck = []

Resets the deck before rebuilding it.

Nested loops

This creates every possible suit-value combination:

  • A♠
  • 2♠
  • 3♠
  • K♣

That gives 52 total cards.

Shuffle loop

This is the Fisher-Yates shuffle pattern.

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]];
}

This randomly swaps cards so the deck is shuffled fairly.


Why This Matters

You are now working with arrays of objects, which is a major step up.

Each card is not just text. It is a data object:

{ value: "K", suit: "♣" }

This makes the code much easier to reason about later.


Developer Insight

A game becomes easier to build when your data matches the real thing.

A card is not “just a string.”
It has parts.

That is one of the most important habits in programming:
model the world clearly.


Vibe Coding Prompt: Generate and Shuffle a Deck

Write a JavaScript function that creates a standard 52-card deck as an array of objects with value and suit properties, then shuffles it using Fisher-Yates.

Why this prompt is good:

  • it names the data format
  • it names the shuffle algorithm
  • it reduces vague output

Step 3 — Draw Cards into Hands

Once the deck exists, we need to deal cards.

A compact version looks like this:

function drawCard(hand) {
if (!deck.length) {
makeDeck();
} hand.push(deck.pop());
}

What This Does

if (!deck.length)

If the deck is empty, rebuild and reshuffle it.

hand.push(deck.pop())

Take the top card from the deck and add it to the chosen hand.

Because the function receives a hand as a parameter, it can be reused for:

  • player
  • dealer

Why This Matters

This is your first strong example of a reusable action function.

Instead of writing:

  • drawPlayerCard()
  • drawDealerCard()

You create one function that works for both.

That is cleaner and more scalable.


Vibe Coding Insight

A good prompt often asks AI for a generic helper function, not a one-off solution.

Better:

Create a reusable function that removes one card from the deck and adds it to a specified hand array.

Worse:

Make the player get a card.

The better prompt produces more reusable code.


Step 4 — Calculate Hand Value

Blackjack scoring is where the game becomes interesting, because not all cards are equal.

A typical scoring function looks like this:

function handValue(hand) {
let total = 0;
let aces = 0; for (const card of hand) {
if (card.value === "A") {
aces++;
total += 11;
} else if (["K", "Q", "J"].includes(card.value)) {
total += 10;
} else {
total += Number(card.value);
}
} while (total > 21 && aces > 0) {
total -= 10;
aces--;
} return total;
}

Line-by-Line Logic

let total = 0

The running score of the hand.

let aces = 0

Tracks how many aces are currently being counted as 11.

Loop through cards

Each card adds value to the hand.

Ace

if (card.value === "A") {
aces++;
total += 11;
}

Start by treating Ace as 11.

Face cards

else if (["K", "Q", "J"].includes(card.value)) {
total += 10;
}

All face cards count as 10.

Number cards

else {
total += Number(card.value);
}

Convert the string like "7" into the number 7.


The Most Important Part: Flexible Ace Logic

while (total > 21 && aces > 0) {
total -= 10;
aces--;
}

If the total is too high and we still have aces counted as 11, we reduce one ace from 11 to 1 by subtracting 10.

Example:

  • Ace + 9 + 8 = 28
  • too high
  • convert Ace from 11 to 1
  • new total = 18

Why This Matters

This function is the heart of Blackjack.

It teaches:

  • iteration
  • conditional logic
  • special-case rules
  • score correction after evaluation

This is a strong example of game rule encoding.


Developer Insight

A lot of game logic works like this:

  1. calculate the optimistic version first
  2. correct it if rules require adjustment

That pattern appears again in:

  • combat modifiers
  • inventory limits
  • movement constraints
  • AI threat evaluation

Vibe Coding Prompt: Ace Logic

Write a JavaScript function to calculate blackjack hand values, including special handling so aces count as 11 unless that would cause the hand to bust, in which case they count as 1.

Why this prompt works:

  • it explains the rule directly
  • it forces AI to solve the real problem, not a simplified one

Step 5 — Start a New Round

Now we combine earlier systems into a round setup.

A typical deal action looks like this:

function dealRound() {
if (state.chips < state.bet) return; makeDeck();
player = [];
dealer = [];
inRound = true; state.chips -= state.bet; drawCard(player);
drawCard(dealer);
drawCard(player);
drawCard(dealer); render(); if (handValue(player) === 21) {
const dealerValue = handValue(dealer); if (dealerValue === 21) {
settleRound("Push on blackjack.", state.bet);
} else {
settleRound("Blackjack! Paid 3:2.", Math.floor(state.bet * 2.5));
}
}
}

What This Does

Check affordability

The player cannot deal a hand if they do not have enough chips.

Reset round state

  • new deck
  • empty hands
  • round becomes active

Deduct the bet

This simulates putting chips on the table.

Deal two cards each

Standard Blackjack opening hand.

Render UI

Update what the player sees.

Check immediate blackjack

If the player hits 21 right away, resolve instantly.


Why This Matters

This function is the first strong example of multi-stage orchestration.

It doesn’t just do one thing. It coordinates:

  • validation
  • setup
  • economy
  • dealing
  • rendering
  • special outcome checking

This is exactly how many real game systems work.


Step 6 — Hit Logic

When the player asks for another card, the game must:

  • draw a card
  • update the UI
  • test for bust

A typical version:

function hitPlayer() {
drawCard(player);
render(); const total = handValue(player); if (total > 21) {
settleRound(`Bust at ${total}.`, 0);
}
}

Logic Breakdown

drawCard(player)

Adds one card to the player’s hand.

render()

Shows the new hand.

handValue(player)

Recalculates the new total.

if (total > 21)

If the player exceeds 21, the round ends.


Why This Matters

This is one of the cleanest examples of action → consequence.

Player action:

  • hit

System consequence:

  • new card
  • new total
  • possible loss

This is the core of interactive game design.


Step 7 — Dealer Logic

The dealer behaves differently from the player.

The player chooses.
The dealer follows fixed rules.

A common implementation:

function standPlayer() {
while (handValue(dealer) < 17) {
drawCard(dealer);
} const playerTotal = handValue(player);
const dealerTotal = handValue(dealer); render(); if (dealerTotal > 21 || playerTotal > dealerTotal) {
settleRound(`Player wins ${playerTotal} vs ${dealerTotal}.`, state.bet * 2);
} else if (playerTotal === dealerTotal) {
settleRound(`Push ${playerTotal}-${dealerTotal}.`, state.bet);
} else {
settleRound(`Dealer wins ${dealerTotal} vs ${playerTotal}.`, 0);
}
}

What This Teaches

Dealer AI does not need to be smart

It only needs to follow clear rules.

while (handValue(dealer) < 17)

Dealer keeps drawing until reaching 17 or more.

Outcome comparison

After both totals are known:

  • bust = lose
  • higher total wins
  • tie = push

Developer Insight

Many games do not need complex AI.

They need:

  • predictable behavior
  • rule consistency
  • understandable outcomes

That is often more important than complexity.


Step 8 — Settling the Round

Now we need a reusable round-ending function.

A typical version:

function settleRound(message, payout) {
inRound = false;
state.chips += payout;
render();
log(message);
}

What This Does

inRound = false

Disables hit and stand actions.

state.chips += payout

Applies:

  • win
  • push
  • blackjack bonus
  • loss

render()

Refreshes the display.

log(message)

Tells the player what happened.


Why This Matters

This is a centralized resolution function.

Instead of scattering “round over” logic everywhere, you funnel all outcomes into one place.

That is cleaner and easier to maintain.


Step 9 — Render the Hands and Scores

Blackjack relies heavily on visual clarity. The player must see:

  • their hand
  • dealer hand
  • score
  • chip count
  • button availability

A rendering pattern often looks like this:

function render() {
chipsEl.textContent = state.chips;
betEl.textContent = state.bet;
playerScoreEl.textContent = handValue(player); if (inRound) {
dealerScoreEl.textContent = handValue(dealer.slice(1));
} else {
dealerScoreEl.textContent = handValue(dealer);
} renderCards(playerCardsEl, player);
renderCards(dealerCardsEl, dealer, inRound); hitBtn.disabled = !inRound;
standBtn.disabled = !inRound;
dealBtn.disabled = inRound;
}

Important UI Ideas Here

Hide one dealer card during the round

That creates suspense and follows Blackjack convention.

Disable buttons based on state

This prevents invalid actions.

Examples:

  • cannot hit before dealing
  • cannot deal again mid-round
  • cannot stand after round ends

Why This Matters

This is your first strong lesson in UI as rule enforcement.

The UI is not just presentation.
It is also part of the system that guides valid play.


Vibe Coding Prompt: Render and Disable Buttons

Update the Blackjack UI from state, including chips, bet, player score, dealer score, rendered cards, and button disabling rules based on whether a round is active.

This works because it asks for:

  • outputs
  • dependencies
  • restrictions

That leads to better structured code.


Step 10 — Event Wiring

Finally, the player’s buttons must connect to the rule system.

A typical event layer:

dealBtn.addEventListener("click", dealRound);
hitBtn.addEventListener("click", hitPlayer);
standBtn.addEventListener("click", standPlayer);
betPlusBtn.addEventListener("click", increaseBet);
betMinusBtn.addEventListener("click", decreaseBet);

This is where UI meets logic.

Each button:

  • triggers one specific action
  • that action changes state
  • the game rerenders

The Full Gameplay Loop

Blackjack is a more advanced loop than the slot machine.

Start

  • player places bet
  • clicks Deal

During round

  • player chooses Hit or Stand

Dealer phase

  • dealer draws until 17+

Resolution

  • compare totals
  • update chips
  • show result
  • unlock next round

That is a real turn-based game loop.


Vibe Coding: How to Build This Well

This is where your book can really stand out.

Do not ask AI:

Build a blackjack game.

That is too broad.

Instead, build in layers.


Recommended Vibe Coding Build Sequence

Prompt 1 — Model the Data

Create the core JavaScript variables and state structure for a blackjack game, including deck, player hand, dealer hand, bet amount, chips, and round status.

Prompt 2 — Build the Deck System

Write a function that creates and shuffles a 52-card deck as objects with value and suit properties.

Prompt 3 — Calculate Scores

Write a blackjack hand scoring function that correctly handles face cards and flexible ace values.

Prompt 4 — Build Round Actions

Create separate JavaScript functions for deal, hit, and stand in a blackjack game, using the deck and hand scoring functions.

Prompt 5 — Render the UI

Update DOM elements for the blackjack table, showing cards, scores, chips, and enabling or disabling buttons depending on round state.

Prompt 6 — Improve the UX

Improve the blackjack game UX by adding clearer messages, better button states, and more visual separation between player and dealer areas.

Why This Prompt Strategy Works

Because each prompt asks AI to solve one layer of the system.

That means:

  • better code quality
  • easier debugging
  • clearer learning
  • less messy outputs

Vibe Coding Rule for This Chapter

Ask AI for systems, not miracles.

That is what makes Vibe Coding useful instead of chaotic.


Common Mistakes in Blackjack Projects

This section is important because best-selling books help readers avoid failure, not just build success.

Mistake 1 — Treating cards like plain strings

That makes score logic harder later.

Mistake 2 — Not separating round state from persistent state

Then the code becomes hard to control.

Mistake 3 — Writing dealer logic inside UI events

That mixes systems together.

Mistake 4 — Forgetting ace correction

This breaks core game rules.

Mistake 5 — Letting invalid actions happen

A player should not be able to hit when no round is active.


Exercises

These exercises are designed to deepen real understanding, not just add busywork.

Exercise 1 — Add Soft/Hard Hand Labels

Show whether the player hand is:

  • soft 17
  • hard 18
  • etc.

This teaches:

  • score interpretation
  • richer UI output

Exercise 2 — Add a Double Down Feature

Rules:

  • only on first decision
  • double the bet
  • draw one card
  • automatically stand

This teaches:

  • action restrictions
  • temporary state rules
  • more complex branching

Exercise 3 — Add Win Statistics

Track:

  • total wins
  • total losses
  • pushes
  • blackjacks

This teaches:

  • persistent stats
  • extra render layers

Exercise 4 — Improve Dealer Reveal

Hide the first dealer card until the round ends.

Then explain in your own words:

  • why suspense matters
  • how hidden information changes player experience

Exercise 5 — Add localStorage

Save:

  • chips
  • bet
  • stats

This teaches:

  • continuity
  • product thinking
  • state persistence

Challenge Mode

Use Vibe Coding to extend the game with one of these prompts:

Prompt: Add Split Hands

Add split hand logic to the blackjack game so the player can split matching opening cards into two hands and play them one at a time.

Prompt: Add Insurance

Add optional insurance to the blackjack game when the dealer shows an ace, and resolve the side bet correctly.

Prompt: Add Table Themes

Add a table theme selector that changes the visual styling of the blackjack table without changing the game logic.

Reflection Questions

Write your answers before moving to Chapter 3.

  1. Why is Blackjack more complex than the slot machine?
  2. What is the most important function in this game, and why?
  3. Why is ace logic a good example of rule encoding?
  4. How does the dealer system differ from player input?
  5. Which parts of this chapter could be reused in Poker Showdown?

Vibe Learning Summary

By the end of this chapter, you should understand that Blackjack is not just a card game.

It is a model of turn-based programming.

You learned how to build and reason about:

  • arrays of objects
  • reusable helper functions
  • rule-based score calculation
  • branching game states
  • turn resolution
  • outcome handling
  • UI-state synchronization

That is a major step forward.


What You Learned That Transfers Forward

This chapter gives you reusable patterns for later projects:

Deck and hand logic

Useful for:

  • Poker
  • RPG loot systems
  • inventory generators

Turn sequence logic

Useful for:

  • Hero Dice
  • tactical combat
  • enemy AI rounds

Outcome comparison

Useful for:

  • battle resolution
  • score contests
  • ranking systems

State-driven button control

Useful for:

  • any UI-heavy game
  • management sims
  • puzzle games

Final Insight

In Chapter 1, you learned that a game is state + rules + input + output.

In Chapter 2, you learn something deeper:

A turn-based game is a conversation between systems.

The player acts.
The rules respond.
The game state changes.
The UI tells the story of that change.

That is real game development.

Next Chapter

In Chapter 3 — Roulette Frontier, you’ll move into:

  • probability-driven outcomes
  • mapping logic to visuals
  • payout structures
  • syncing game results with interface feedback

That chapter will help you think more deeply about randomness, fairness, and presentation.

Chapter 3 — Roulette Frontier

Build a Probability Game with Mapped Outcomes, Betting Logic, and Visual Feedback

In Chapter 1, you built a slot machine and learned the basics of state, randomness, and UI updates.

In Chapter 2, Blackjack Command introduced turn-based logic, branching decisions, and rule-driven scoring.

Now we move into a different kind of game:

a game where the core tension comes from probability, betting, and presentation

Roulette is powerful for learning JavaScript because it teaches you how to connect:

  • a visible interface
  • a hidden result
  • a mapped set of outcomes
  • payout rules
  • player bets
  • persistent bankroll state

It also introduces a deeper lesson:

not all randomness feels trustworthy unless the presentation matches the logic

That is exactly why Roulette Frontier matters in this book.
It is not just about spinning a wheel. It is about making the logic and the visible result feel aligned.


The Vibe Learning Focus for This Chapter

This chapter follows the same Vibe Learning structure:

Curiosity

How do roulette games map numbers, colors, and bets into a system that feels fair and understandable?

Build

Create a roulette game with:

  • bankroll
  • bet controls
  • a visible wheel
  • result history
  • payout logic
  • saved progress

Explain

Break down the code into:

  • probability model
  • wheel order
  • rotation logic
  • payout system
  • UI feedback

Refine

Use Vibe Coding prompts to improve:

  • clarity
  • alignment
  • visual trust
  • reliability

Extend

Add deeper betting options and better UX.


The Real Goal of This Chapter

You are not just building roulette.

You are learning how to build a mapped outcome system.

That means:

  • every number belongs somewhere
  • every number has a color
  • every bet must connect to clear rules
  • the visible UI must match the hidden logic
  • the player must trust the result

This is one of the most important ideas in game development:

A game can be logically correct and still feel wrong if the presentation does not support the logic.


What We Are Building

In Roulette Frontier, the player can:

  • place a bet amount
  • choose a bet type:
    • red
    • black
    • even
    • odd
    • single number
  • spin the wheel
  • see the result
  • receive a payout if the bet wins
  • track recent spin history
  • keep bankroll progress with localStorage

This chapter teaches strong JavaScript skills because it combines:

  • number mapping
  • visual state
  • persistent state
  • conditional payouts
  • interface feedback

System Overview

Before code, let’s break Roulette Frontier into systems.

SystemResponsibility
Bankroll SystemTracks player money
Bet SystemStores bet amount and bet type
Wheel Order SystemDefines number placement
Color Mapping SystemDetermines red, black, green
Spin SystemGenerates a winning number
Payout SystemDecides win/loss and returns money
UI SystemUpdates wheel, labels, history, and messages
Persistence SystemSaves bankroll and last results

Again, this is Vibe Coding thinking:

build the game as connected systems, not as one giant blob of code


Step 1 — Persistent State

A roulette game needs to remember more than just one result. It needs to store player progress and UI-related state.

A typical structure from this project looks like this:

const state = loadState();
let selectedType = state.selectedType || "red";
let spinning = false;
let wheelRotation = Number.isFinite(state.wheelRotation) ? state.wheelRotation : 0;

And the stored object looks like this:

{
bankroll: 500,
betAmount: 20,
numberPick: 17,
selectedType: "red",
wheelRotation: 0,
lastResult: null,
lastNet: 0,
history: []
}

What Each Part Means

bankroll

How much money the player currently has.

betAmount

The amount risked on the next spin.

numberPick

Used only when the player selects a single number bet.

selectedType

Stores which bet type is active.

wheelRotation

Stores the current rotation angle so the wheel can continue from its last state.

lastResult

Stores the most recent winning number and its color.

lastNet

Stores the profit or loss from the last spin.

history

Stores recent past spins for the result board.


Why This Matters

This is more advanced than Chapter 1 because the state now includes both:

  • gameplay information
  • interface memory

That makes the experience feel more polished.


Developer Insight

A lot of modern interfaces store not only game state, but also presentation continuity.

Examples:

  • wheel rotation
  • selected tab
  • last filter
  • saved theme
  • expanded menu state

That is a product-level design mindset.


Vibe Coding Prompt: State Design

Create the saved state structure for a JavaScript roulette game. Include bankroll, bet amount, selected bet type, picked number, wheel rotation, last result, last profit or loss, and recent spin history.

Why this is a strong prompt:

  • it asks for a system blueprint
  • it gives AI clear constraints
  • it avoids vague all-in-one code dumps

Step 2 — The Wheel Order

Roulette is not random numbers in a random list. The wheel has a specific order.

In the project, that order is stored like this:

const WHEEL_ORDER = [
0, 32, 15, 19, 4, 21, 2, 25, 17, 34, 6, 27, 13, 36, 11, 30, 8, 23,
10, 5, 24, 16, 33, 1, 20, 14, 31, 9, 22, 18, 29, 7, 28, 12, 35, 3, 26
];

Why This Array Matters

This array is the wheel map.

It answers:

  • what numbers exist
  • how many there are
  • where they appear around the circle

Without this array, you do not have a roulette wheel.
You only have a random number generator.

That distinction matters.


Developer Insight

A lot of games depend on a “map array” like this:

  • board games
  • tile maps
  • level layouts
  • attack order
  • enemy waves
  • wheel positions

If you understand this array, you understand the geometry of the system.


Step 3 — Color Mapping

Roulette also needs to know whether a number is red, black, or green.

A typical implementation looks like this:

const RED_NUMBERS = new Set([
1, 3, 5, 7, 9, 12, 14, 16, 18,
19, 21, 23, 25, 27, 30, 32, 34, 36
]);function colorFor(number) {
if (number === 0) return "green";
return RED_NUMBERS.has(number) ? "red" : "black";
}

Code Breakdown

new Set([...])

A Set is used because it makes membership checks clean and fast.

if (number === 0)

Roulette zero is green.

RED_NUMBERS.has(number)

If the number is in the red set, return red. Otherwise it must be black.


Why This Matters

This is a strong example of data-driven logic.

Instead of writing:

if (number === 1 || number === 3 || number === 5 ...)

you build a data structure once and reuse it cleanly.

That is better code and better design.


Vibe Coding Prompt: Color Logic

Create a JavaScript function for roulette that returns green for 0, red for official red numbers, and black for all other numbers.

Why it works:

  • clearly defines the edge case
  • specifies the expected outputs
  • turns vague behavior into testable logic

Step 4 — Building the Wheel UI

In the simplified premium version, the wheel is built with HTML/CSS slots instead of a more fragile canvas labeling system.

A typical function looks like this:

function buildWheel(highlightNumber = null) {
wheelEl.innerHTML = ""; WHEEL_ORDER.forEach((num, index) => {
const slot = document.createElement("div");
slot.className = `slot ${colorFor(num)}${num === highlightNumber ? " active" : ""}`;
slot.style.transform = `rotate(${index * SEGMENT_DEG}deg)`; const label = document.createElement("div");
label.className = "slot-label";
label.textContent = num; slot.appendChild(label);
wheelEl.appendChild(slot);
}); wheelEl.style.transform = `rotate(${wheelRotation}deg)`;
}

Line-by-Line Logic

wheelEl.innerHTML = ""

Clear any old slots before rebuilding.

WHEEL_ORDER.forEach(...)

Create one visible slot per number.

slot.className = ...

Apply:

  • red / black / green styles
  • active highlight if this was the winning number

slot.style.transform = rotate(...)

Place each slot around the wheel using its index.

label.textContent = num

Show the number visibly.

wheelEl.style.transform = rotate(...)

Rotate the entire wheel to its current angle.


Why This Matters

This is a strong lesson in presentation driven by data.

You are not hardcoding each slot manually.
You are generating the interface from a system map.

That means:

  • fewer mistakes
  • easier updates
  • better alignment with logic

Developer Insight

When UI can be generated from data, it becomes more reliable.

That is especially useful in:

  • game boards
  • enemy panels
  • card hands
  • upgrade trees
  • result histories

Step 5 — Bet Type and Payout Display

The player needs immediate feedback about what kind of bet is selected and what the expected payout is.

A rendering helper might look like this:

function payoutText(type) {
return type === "number" ? "36x total return" : "2x total return";
}

And the UI update function:

function renderButtons() {
document.querySelectorAll(".bet-btn").forEach(btn => {
btn.classList.toggle("selected", btn.dataset.type === selectedType);
}); selectedBetEl.textContent =
selectedType === "number"
? `Single Number (${Number(numberPickEl.value) || 0})`
: selectedType.charAt(0).toUpperCase() + selectedType.slice(1); selectedPayoutEl.textContent = payoutText(selectedType);
}

What This Does

Highlight selected bet type

The player sees what bet is currently active.

Update label text

The UI reflects either:

  • Red
  • Black
  • Even
  • Odd
  • Single Number (17)

Show payout rule

The player understands the risk/reward before spinning.


Why This Matters

A good game interface reduces uncertainty about rules.

This is especially important in betting systems because confusion feels unfair.


Step 6 — Spinning the Wheel

Now we reach the visible motion system.

First, the game needs to know where a number appears on the wheel:

function indexOfNumber(number) {
return WHEEL_ORDER.indexOf(number);
}

Then it needs to calculate how far to rotate:

function computeFinalRotation(number) {
const idx = indexOfNumber(number);
const targetMod = (360 - (idx * SEGMENT_DEG)) % 360;
const currentMod = ((wheelRotation % 360) + 360) % 360;
const delta = (targetMod - currentMod + 360) % 360;
return wheelRotation + 1440 + delta;
}

Why This Looks More Complex

Because the game must solve two problems:

1. Put the correct number under the fixed pointer

That is what targetMod is for.

2. Spin naturally from the current position

That is why the code uses:

  • current rotation
  • modular math
  • several extra turns (1440, or four full spins)

Line-by-Line Explanation

const idx = indexOfNumber(number)

Find where the number sits in the wheel order.

const targetMod = ...

Figure out the angle required to place that slot under the pointer.

const currentMod = ...

Normalize the current wheel angle into a 0–359 range.

const delta = ...

Compute how much more rotation is needed to land correctly.

return wheelRotation + 1440 + delta

Add four full turns plus the exact needed adjustment.

This gives a result that:

  • spins dramatically
  • still lands on the correct number

Developer Insight

This is a classic example of animation math that serves logic.

The motion is not random.
It is a calculated performance layer on top of a fixed outcome.

That is how many games work.

Examples:

  • battle animations
  • loot chest reveals
  • wheel spins
  • slot reels
  • card flips

The outcome is known first.
The animation is designed to deliver it convincingly.


Vibe Coding Prompt: Rotation Math

Given a roulette wheel order array and a fixed pointer at the top, calculate the final rotation angle needed so a chosen number lands under the pointer after several full spins.

This is a great prompt because it asks AI for a math-specific helper, not an entire game.


Step 7 — Resolving the Spin

Once the result number is known, the game needs to determine whether the bet wins.

A core resolution function looks like this:

function resolveSpin(number, type, bet, numberPick) {
const color = colorFor(number);
let payout = 0; if (type === "red" && color === "red") payout = bet * 2;
if (type === "black" && color === "black") payout = bet * 2;
if (type === "even" && number !== 0 && number % 2 === 0) payout = bet * 2;
if (type === "odd" && number % 2 === 1) payout = bet * 2;
if (type === "number" && number === numberPick) payout = bet * 36; state.bankroll -= bet;
state.bankroll += payout; state.lastResult = { number, color };
state.lastNet = payout - bet;
state.history.unshift({ number, color, type, bet, numberPick, net: state.lastNet });
state.history = state.history.slice(0, 20);
}

Code Breakdown

const color = colorFor(number)

Find the result color.

let payout = 0

Assume loss unless proven otherwise.

Conditional payouts

Each bet type checks its own win rule.

Red / Black

Straight color match.

Even

Must be even and not zero.

Odd

Must be odd.

Single Number

Must match exactly.


Important Detail: Net Result

state.lastNet = payout - bet;

This makes result messaging clearer.

Examples:

  • bet 20, payout 40 → net +20
  • bet 20, payout 0 → net -20

This is better than only showing payout because it tells the player the actual outcome.


Why This Matters

This function is the outcome engine.

It:

  • applies rules
  • changes bankroll
  • records result state
  • updates history data

That is the heart of the roulette game.


Step 8 — The Spin Action

Now we connect:

  • validation
  • animation
  • outcome resolution

A typical spin function:

function spin() {
const bet = Number(betAmountEl.value);
const numberPick = Number(numberPickEl.value); if (!bet || bet < 10) {
resultBannerEl.className = "result-banner lose";
resultBannerEl.textContent = "Enter a valid bet of at least 10.";
return;
} if (bet > state.bankroll) {
resultBannerEl.className = "result-banner lose";
resultBannerEl.textContent = "You do not have enough bankroll for that bet.";
return;
} if (selectedType === "number" && (Number.isNaN(numberPick) || numberPick < 0 || numberPick > 36)) {
resultBannerEl.className = "result-banner lose";
resultBannerEl.textContent = "Choose a number from 0 to 36.";
return;
} spinning = true;
renderStats(); const result = Math.floor(Math.random() * 37);
wheelRotation = computeFinalRotation(result);
wheelEl.style.transform = `rotate(${wheelRotation}deg)`; setTimeout(() => {
resolveSpin(result, selectedType, bet, numberPick);
saveState();
spinning = false;
renderStats();
}, 3650);
}

What This Teaches

Validation first

Before spinning:

  • bet must be valid
  • bankroll must cover it
  • single-number picks must be legal

Freeze the UI

spinning = true disables repeated interaction during the animation.

Generate the result

const result = Math.floor(Math.random() * 37);

That gives 0–36.

Animate to that result

The wheel is rotated to land on the chosen number.

Resolve after delay

Only after the animation finishes:

  • bankroll updates
  • history updates
  • labels rerender

Developer Insight

This is a good example of separating event timing from game logic.

The result is chosen immediately.
The player sees it later.

That creates anticipation without changing the rule system.


Step 9 — Result Rendering

After a spin, the player should instantly understand:

  • what number hit
  • what color it was
  • whether they won or lost
  • how much they gained or lost

That is what the result banner does:

function renderBanner() {
if (!state.lastResult) {
resultBannerEl.className = "result-banner neutral";
resultBannerEl.textContent = "Place a bet and spin.";
return;
} const r = state.lastResult;
resultBannerEl.className = `result-banner ${state.lastNet >= 0 ? "win" : "lose"}`;
resultBannerEl.textContent =
`Wheel landed on ${r.number} (${r.color.toUpperCase()}) · ${state.lastNet >= 0 ? "Win" : "Loss"} ${Math.abs(state.lastNet)}`;
}

Why This Matters

The player should never need to mentally decode the game state.

A strong interface translates the logic into meaning instantly.

That is a best-seller-level teaching point because many beginner books explain how to code, but not how to communicate outcomes.


Step 10 — History Rendering

The result history helps make the game feel real and trackable.

A typical rendering function:

function renderHistory() {
historyEl.innerHTML = ""; if (!state.history.length) {
historyEl.innerHTML = "<div class='history-item'>No spins yet.</div>";
return;
} state.history.slice(0, 12).forEach(item => {
const row = document.createElement("div");
row.className = "history-item";
row.innerHTML = `
<div>
<div><strong>${item.number}</strong> ${item.color.toUpperCase()}</div>
<div class="muted">Bet: ${item.type}${item.type === "number" ? ` (${item.numberPick})` : ""} · ${item.bet}</div>
</div>
<div class="history-pill ${item.color}">
${item.net >= 0 ? "+" + item.net : item.net}
</div>
`;
historyEl.appendChild(row);
});
}

What This Teaches

  • how to render repeated UI from data
  • how to format result summaries
  • how to build a “story” of previous actions

This pattern shows up everywhere in modern apps:

  • notifications
  • score history
  • transaction lists
  • combat logs
  • order history

Vibe Coding: How to Build This Chapter Well

This chapter is a perfect example of where Vibe Coding must be intentional.

Do not ask:

Make a roulette game.

That is too vague and often creates mismatched logic and visuals.

Instead, prompt in layers.


Recommended Vibe Coding Sequence

Prompt 1 — Model the Game State

Create the JavaScript state structure for a roulette game, including bankroll, bet amount, selected bet type, picked number, recent history, and last result.

Prompt 2 — Create the Wheel Order

Store the roulette wheel number order in a JavaScript array and write a helper to find the index of a number in that order.

Prompt 3 — Build the Color System

Write a JavaScript helper function that returns red, black, or green for roulette numbers, using the official red number set and green for zero.

Prompt 4 — Build the Payout Logic

Create a function that resolves roulette bets for red, black, odd, even, and single-number bets, then updates bankroll and history.

Prompt 5 — Solve the Rotation Math

Calculate the final CSS rotation needed to spin a roulette wheel several full turns and land a selected number under a fixed pointer.

Prompt 6 — Improve the UI Rendering

Render roulette history, selected bet info, last result, and bankroll from state in a polished JavaScript UI.

Why This Prompt Strategy Works

Because each prompt asks AI to build a specific subsystem.

That produces:

  • cleaner code
  • easier debugging
  • more reusable logic
  • better understanding

Vibe Coding Rule for This Chapter

When logic and visuals must match, prompt for them separately, then test them together.

That is the key lesson here.


Common Mistakes in Roulette Projects

This section matters because readers trust books that help them avoid pain.

Mistake 1 — Using random numbers without a real wheel map

Then the interface feels fake.

Mistake 2 — Showing a wheel result that does not match the actual logic

This destroys player trust.

Mistake 3 — Hardcoding messy payout conditions everywhere

Instead, centralize them.

Mistake 4 — Forgetting zero rules

Zero is green and is neither odd nor even.

Mistake 5 — Making the animation more complex than necessary

A simpler wheel that is always accurate is better than a flashy one that feels wrong.


Exercises

These exercises are designed to help the reader think like a builder.

Exercise 1 — Add Low / High Bets

Add:

  • 1–18
  • 19–36

This teaches:

  • range-based conditions
  • expanding payout systems

Exercise 2 — Add Dozen Bets

Allow bets on:

  • 1–12
  • 13–24
  • 25–36

This teaches:

  • grouped probability rules
  • scalable condition handling

Exercise 3 — Add Better Bankroll Messaging

Show messages like:

  • “You won 20”
  • “You lost 20”
  • “Exact number hit!”

This teaches:

  • stronger player feedback
  • message formatting

Exercise 4 — Add Win / Loss Statistics

Track:

  • total spins
  • total wins
  • total losses
  • biggest win

This teaches:

  • persistent analytics state

Exercise 5 — Build a Flat Table Layout

Add a visual betting board with clickable number cells.

This teaches:

  • UI mapping
  • interactive selection
  • game-table design

Challenge Mode Prompts

Prompt: Add Dozens and Columns

Expand the roulette game so the player can also bet on dozens and columns, and update the payout logic accordingly.

Prompt: Add a Betting Table UI

Create a clickable roulette betting table layout with number cells, color bets, and even/odd areas that update the current selected bet.

Prompt: Add Spin Sound and Win Feedback

Improve the roulette game by adding optional sound effects, a winning highlight, and stronger result messages after each spin.

Reflection Questions

  1. Why does roulette depend so heavily on trust between logic and visuals?
  2. What role does the wheel order array play in the game?
  3. Why is 0 a useful example of a special-case rule?
  4. What is the most important function in this chapter, and why?
  5. Why is a simpler but accurate wheel better than a visually impressive but unreliable one?

Vibe Learning Summary

By the end of this chapter, you should understand that Roulette Frontier is not just a probability game.

It is a mapping game.

You learned how to connect:

  • data structures
  • visual layout
  • random outcomes
  • payout conditions
  • stored history
  • interface trust

That is a major design lesson.


What Transfers Forward

This chapter prepares you for later games in several ways:

Mapping systems

Useful for:

  • puzzle boards
  • level layouts
  • enemy formations

Payout / reward logic

Useful for:

  • trading systems
  • combat rewards
  • progression systems

Visual alignment with logic

Useful for:

  • action games
  • tactical games
  • management interfaces

History rendering

Useful for:

  • logs
  • stats
  • battle histories
  • transaction records

Final Insight

In Chapter 1, you learned that games are systems.
In Chapter 2, you learned that turn-based systems are structured conversations.

In Chapter 3, you learn something even more subtle:

Players trust what they can see only when it matches the logic underneath.

That is not just a roulette lesson.

That is a game design lesson.


Next Chapter

In Chapter 4 — Poker Showdown, you’ll step into:

  • hand ranking
  • pattern detection
  • sorted arrays
  • multi-stage game flow

That chapter will push you further into algorithmic thinking and reusable scoring systems.