Add Casino demo section with a Texas Hold'em dealer's pot-splitting assistant

New /casino hub page (Texas Hold'em live, other table games marked coming
soon) and /casino/texasholdem: a drag-and-drop seating table with
auto-rotating blinds, per-seat chip/dollar contribution tracking, and a
side-pot resolution wizard that asks who won and who's next until every
dollar in the pot (including dead money from folds) is assigned.

Co-Authored-By: Claude Sonnet 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_018CmAti1baCjidbJM2HeJfk
This commit is contained in:
2026-08-31 14:25:44 -06:00
co-authored by Claude Sonnet 5
parent b7c9227bb8
commit 98f95df8fb
13 changed files with 1721 additions and 1 deletions
+49
View File
@@ -0,0 +1,49 @@
@page
@model JoshHeaps.Net.Pages.CasinoModel
@{
ViewData["Title"] = "Casino Games";
Layout = "_Layout";
}
<div class="casino-container">
<h1 class="casino-header">Casino Games</h1>
<p class="casino-subtitle">Tools for running table games without doing the math yourself</p>
<div class="games-grid">
<a href="/casino/texasholdem" class="game-card">
<div class="game-icon">🃏</div>
<div class="game-title">Texas Hold'em</div>
<div class="game-description">
A dealer's assistant: seat players around the table, track blinds, chips and
all-ins, then split main and side pots automatically.
</div>
</a>
<div class="game-card disabled">
<div class="game-icon">🎲</div>
<div class="game-title">Craps</div>
<div class="game-description">Payout calculator for the table.</div>
<div class="coming-soon">Coming soon...</div>
</div>
<div class="game-card disabled">
<div class="game-icon">🎡</div>
<div class="game-title">Roulette</div>
<div class="game-description">Bet tracking and payout reference.</div>
<div class="coming-soon">Coming soon...</div>
</div>
<div class="game-card disabled">
<div class="game-icon">🂡</div>
<div class="game-title">Blackjack</div>
<div class="game-description">Multi-hand dealer tracker.</div>
<div class="coming-soon">Coming soon...</div>
</div>
</div>
<a href="/" class="home-button">← Back to Home</a>
</div>
@section Styles {
<link href="/css/casino/page.css?v=@ViewData["cssVersion"]" rel="stylesheet" type="text/css" />
}
+11
View File
@@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace JoshHeaps.Net.Pages
{
public class CasinoModel : PageModel
{
public void OnGet()
{
}
}
}
@@ -0,0 +1,159 @@
@page
@model JoshHeaps.Net.Pages.Casino.TexasHoldemModel
@{
ViewData["Title"] = "Texas Hold'em Dealer";
Layout = "_Layout";
}
<div id="holdemApp">
<header id="holdemHeader">
<div id="holdemHeaderLeft">
<h1>Texas Hold'em Dealer</h1>
<p class="holdemSubtitle">Seat your players, track the action, split the pot.</p>
</div>
<div id="holdemHeaderActions">
<button id="nextHandBtn" class="holdemBtn" title="Move the button, small blind and big blind to the next occupied seat">Next Hand ⟳</button>
<button id="resolvePotBtn" class="holdemBtn holdemBtnAccent">Resolve Pot</button>
<button id="resetTableBtn" class="holdemBtn holdemBtnDanger">Reset Table</button>
<a href="/casino" class="holdemBtn holdemBtnGhost">← Casino</a>
</div>
</header>
<div id="holdemLayout">
<section id="tableSection">
<div id="pokerTableWrap">
<div id="pokerTable">
<div id="potBadge">
<span id="potBadgeLabel">Pot</span>
<span id="potBadgeAmount">$0</span>
</div>
</div>
<div id="seatsLayer"></div>
</div>
<p class="tableHint">Drag a seat onto another seat to swap players. Click the dealer chip on a seat to make it the button.</p>
</section>
<aside id="holdemSidebar">
<details class="sidebarPanel" open>
<summary>Table Setup</summary>
<div class="panelBody">
<label class="fieldRow">
<span>Seats at table</span>
<input type="number" id="seatCountInput" min="2" max="24" value="10" />
</label>
<label class="fieldRow">
<span>Blinds move</span>
<select id="directionSelect">
<option value="clockwise" selected>Clockwise</option>
<option value="counterclockwise">Counterclockwise</option>
</select>
</label>
<label class="fieldRow">
<span>Base pot amount ($)</span>
<input type="number" id="basePotInput" min="0" step="1" placeholder="e.g. 500" />
</label>
<p class="fieldHint">Every player who didn't go all-in short is assumed to have put in this amount. Enter a smaller amount on a seat only if that player is all-in for less.</p>
</div>
</details>
<details class="sidebarPanel">
<summary>Chip Legend</summary>
<div class="panelBody">
<div id="chipLegendList"></div>
<button id="addChipColorBtn" class="holdemBtn holdemBtnSmall">+ Add chip color</button>
<p class="fieldHint">Give each chip color a dollar value, then count chips per seat instead of typing a total.</p>
</div>
</details>
<details class="sidebarPanel">
<summary>Table Notes</summary>
<div class="panelBody">
<textarea id="tableNotes" rows="4" placeholder="Anything else worth tracking — side bets, IOUs, running totals..."></textarea>
</div>
</details>
</aside>
</div>
</div>
<template id="seatTemplate">
<div class="seat" draggable="true">
<div class="seatChairNumber"></div>
<button class="dealerChip" title="Make this seat the dealer button">D</button>
<span class="blindBadge sbBadge">SB</span>
<span class="blindBadge bbBadge">BB</span>
<div class="seatCard">
<div class="seatCardTop">
<input type="text" class="seatNameInput" placeholder="Seat" maxlength="24" />
</div>
<div class="seatCardToggles">
<label class="inHandToggle" title="This seat is playing the current hand">
<input type="checkbox" class="inHandCheckbox" />
<span>In hand</span>
</label>
<label class="foldToggle" title="Folded">
<input type="checkbox" class="foldCheckbox" />
<span>Fold</span>
</label>
</div>
<div class="seatCards">
<input type="text" class="cardInput card1Input" maxlength="2" placeholder="__" />
<input type="text" class="cardInput card2Input" maxlength="2" placeholder="__" />
</div>
<div class="seatContribution">
<div class="chipCounts"></div>
<label class="fieldRow amountOverrideRow">
<span>$ amount</span>
<input type="number" class="amountOverrideInput" min="0" step="1" placeholder="auto" />
</label>
<div class="seatTotal">Total: <span class="seatTotalAmount">$0</span></div>
</div>
<div class="customFields"></div>
<button class="holdemBtn holdemBtnSmall addFieldBtn">+ field</button>
</div>
</div>
</template>
<template id="chipLegendRowTemplate">
<div class="chipLegendRow">
<input type="color" class="chipColorInput" />
<input type="number" class="chipValueInput" min="0" step="0.01" placeholder="value" />
<button class="holdemBtn holdemBtnSmall holdemBtnDanger removeChipColorBtn">×</button>
</div>
</template>
<template id="chipCountTemplate">
<label class="chipCountRow">
<span class="chipSwatch"></span>
<input type="number" class="chipCountInput" min="0" step="1" value="0" />
</label>
</template>
<template id="customFieldTemplate">
<div class="customFieldRow">
<input type="text" class="customFieldLabel" placeholder="Label" maxlength="20" />
<input type="text" class="customFieldValue" placeholder="Value" maxlength="40" />
<button class="holdemBtn holdemBtnSmall holdemBtnDanger removeFieldBtn">×</button>
</div>
</template>
<div id="potWizardOverlay" hidden>
<div id="potWizardModal">
<div class="potWizardHeader">
<h2>Resolve the Pot</h2>
<button id="closePotWizardBtn" class="holdemBtn holdemBtnGhost">✕</button>
</div>
<div id="potWizardBody"></div>
</div>
</div>
@section Styles {
<link href="/css/casino/holdem.css?v=@ViewData["cssVersion"]" rel="stylesheet" type="text/css" />
}
@section Scripts {
<script src="~/js/casino/holdem/potCalculator.js?v=@ViewData["cssVersion"]"></script>
<script src="~/js/casino/holdem/state.js?v=@ViewData["cssVersion"]"></script>
<script src="~/js/casino/holdem/render.js?v=@ViewData["cssVersion"]"></script>
<script src="~/js/casino/holdem/potWizard.js?v=@ViewData["cssVersion"]"></script>
<script src="~/js/casino/holdem/main.js?v=@ViewData["cssVersion"]"></script>
}
@@ -0,0 +1,11 @@
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace JoshHeaps.Net.Pages.Casino
{
public class TexasHoldemModel : PageModel
{
public void OnGet()
{
}
}
}
+1
View File
@@ -64,6 +64,7 @@
<button class="demoButton" onclick="window.location.href='/watch'">Watch Live Chess</button>
<button class="demoButton" onclick="window.location.href='/particles'">Particle Simulator</button>
<button class="demoButton" onclick="window.location.href='/memorylane'">Memory Lane</button>
<button class="demoButton" onclick="window.location.href='/casino'">Casino Games</button>
<button class="demoButton" onclick="window.location.href='https://media.joshheaps.net'">Cloud Image Storage</button>
<button id="MoreFiller" class="demoButton">More coming soon...</button>
</div>
+1 -1
View File
@@ -1,6 +1,6 @@
@{
Layout = null;
ViewData["cssVersion"] = "1.0.7"; // <--- change this once to bust cache
ViewData["cssVersion"] = "1.0.8"; // <--- change this once to bust cache
}
<!DOCTYPE html>