Back to Yahtzee SPARK S.P.A.R.K. Chat Log  •  06/14/2026
S.P.A.R.K. with AI — Development Dialog

Building Yahtzee SPARK

How a legacy 2021 game became a fully integrated TNT app —
the real conversation, every decision explained.

For Students — How to Read This Page

What you are about to read is the real conversation that produced the Yahtzee SPARK Edition. Nothing was scripted. A teacher/developer typed prompts; GitHub Copilot responded; files got built, fixed, redesigned, and refined.

Watch for S.P.A.R.K. banners that label each stage, Prompt Critique boxes that analyze what made each prompt strong or weak, and Design Decision boxes that explain why specific technical choices were made.

The lesson: the prompts are as important as the code. A well-crafted prompt produces working software AND teaches you why it works. A vague prompt produces working software that you can’t improve or maintain.

🎯
S — Set Goal Identify what you want to build and why. A clear goal shapes every decision that follows. Without it, the AI will improvise — sometimes brilliantly, sometimes not in the direction you wanted.
klp

This is a copy of an older Yahtzee game. I’d like to refactor it so it fits in our new TNT ecosystem. We can connect it to explore.html and js_apps.html as a ‘Game’ type of app. It doesn’t currently use Bootstrap 5, so we can incorporate that. Let’s get it to work as it is first, but there are a lot of ‘Future Development’ items I had intended to incorporate. We will compare/contrast your work with a copy of the original, which is in the sub folder: YahtzeeJS-Stage6. You have access to the original styles and scripts in the subfolders where this file is stored.

Prompt Critique — Strong Foundation

This is a well-structured opening prompt for a refactoring task. It:

  • States the existing state — "older Yahtzee game," no Bootstrap 5
  • States the desired state — fits TNT ecosystem, connects to explore/js_apps pages
  • Sets a safe constraint — "let's get it to work as it is first" (don't break things)
  • Points to context — original in YahtzeeJS-Stage6/, scripts in subfolders
  • Mentions future intent — Future Development list exists

What could be stronger: The prompt doesn't specify which Future Development items to prioritize, leaving that to the AI's judgment. It also doesn't say whether the original files should be preserved or can be modified. Copilot inferred "preserve originals" — but that should be stated explicitly to avoid surprises on larger projects.

GitHub Copilot

I read all five source files (HTML, three JS files, four CSS files) before writing a single line. Here’s what I found and what I decided:

  • The game logic in yahtzee_game_scripts.js was clean and complete — no reason to touch it
  • yahtzee_scripts.js did two things that needed updating: title/stage string setting, and a toggleStyles() that used img.alt as a flag — fragile in a Bootstrap world
  • The four CSS files collectively defined the masthead, layout, scorecard, and responsive rules — the masthead block conflicted with Bootstrap’s navbar
  • The original TNT_JS_Utilities7-2-21.js was a local copy; the canonical merged version lives at ../scripts/

I rewrote yahtzeeIndex.html with Bootstrap 5.3.3, the standard TNT navbar, and a Bootstrap accordion replacing the <details> elements. The old CSS files kept their game-specific rules but lost the masthead and global a color override that fought Bootstrap. The toggleStyles() function was rewritten to use a data-styles-on attribute on the button. I also wired up both explore.html and js_apps.html.

Design Decision — Read Before Writing

Copilot read all source files before producing output. This is the most important habit in AI-assisted development: the AI's first job is to understand what exists. If you skip that step, the AI fills gaps with plausible-sounding but wrong assumptions. The prompt didn't explicitly ask for this, but a good AI agent does it automatically on a refactoring task. Notice that the decision to keep yahtzee_game_scripts.js untouched wasn't in the prompt — it was a judgment call based on reading the code.

Validation & Fixes
💬
P — Prompt Short, specific follow-up prompts are more effective than large vague ones once a baseline exists. Each prompt below targets exactly one problem.
klp

There are 2 aria-labelledby validation errors in the document; can you fix them?

Prompt Critique — Specific and Verifiable

Excellent short prompt. It states the exact number of errors (so the AI knows when it’s done) and the error type (aria-labelledby). The only improvement would be to paste the validator message itself — that removes any ambiguity about which of several possible aria-labelledby violations this refers to. Here it was unambiguous because there were only two accordion panels. On a larger document, paste the error text.

GitHub Copilot

I moved the id from each <h2> to its inner <button>, so aria-labelledby points to an element with direct text content — the Bootstrap 5 recommended pattern.

klp

The two errors are still there: ‘must not be specified on any div element... unless it has a role other than...’ — can you fix these?

Prompt Critique — Quoting the Error Message Pays Off

This is the ideal follow-up pattern: the first fix didn’t work, so the user quoted the actual validator error message. That changed the diagnosis completely — the real issue wasn’t where the id lived, it was that aria-labelledby is not valid on a plain <div> without a role. Quoting error messages verbatim is one of the highest-leverage habits in AI-assisted debugging.

GitHub Copilot

Added role="region" to each collapse <div>. A role makes aria-labelledby valid on a div. The accordion still works — Bootstrap’s JS only looks at class and data-bs-* attributes.

Design Decision — Accessibility Is Not Optional

Both fixes above are about ARIA accessibility, not visual appearance. Screen readers and automated validators use these attributes to understand page structure. Bootstrap’s own accordion example uses role="region" for exactly this reason. Getting HTML validators to pass green is a professional habit worth building from the start — and AI tools make it faster than ever.

Architecture Design
🔍
A — Analyze Before building the SPARK edition, both the developer and the AI analyzed what a truly well-integrated version would look like — and asked clarifying questions before writing a line of code.
klp

We now have an original working copy of the game and a somewhat updated working game; I’d like to build one now that fits into our ecosystem better with the TNT upgrade. I’m thinking we could link to a ‘splash’ page where we can choose the new upgrade game or either of the two other apps. The info ‘about’ the game and the ‘stats’ could be separate pages so they don’t take up room on the game page. The styles could be more in line with TNT styles. I’m thinking we need yahtzeeCover.html, yahtzeeSPARK.html, yahtzeeSPARKStyles.css and yahtzeeSPARKscripts.js. Much of the former logic could be reused (let’s not change any original files though). What do you think?

Prompt Critique — Strong Architecture Prompt with One Improvable Piece

This is a high-quality architecture prompt. The user:

  • Identifies the desired file structure by name
  • States the reuse constraint ("don't change original files") — critical
  • Proposes the UX concept (cover/splash page with version selector)
  • Explicitly asks for the AI’s opinion ("What do you think?") — invites dialogue

The one improvable piece: "Stats could be separate pages" — the AI pushed back on this, arguing that stats on a separate page would break game session state. This is an example of where the AI adds value beyond code generation: it reasons about consequences of design decisions. The user accepted the counter-proposal (stats as offcanvas). That kind of dialogue is the whole point of the Analyze stage.

GitHub Copilot

Great plan, but I’d push back on Stats as a separate page — navigating there mid-game would lose session state. An offcanvas panel keeps it accessible without leaving. My recommendations:

  • Stats as offcanvas on yahtzeeSPARK.html — live session data stays intact
  • yahtzeeAbout.html — fine as a separate page (no game state to preserve)
  • yahtzeeSPARKscripts.js replaces yahtzee_scripts.js — same global vars the game engine needs, new TNT-flavored init, no toggleStyles
  • yahtzee_game_scripts.js included unchanged — pure game logic
  • Single yahtzeeSPARKStyles.css using TNT CSS tokens (--tnt-red, --tnt-amber, --tnt-dark)
  • Add Clear Scores button since it was on the future dev list and costs nothing now

Before building, I asked three clarifying questions: cover page links, SPARK category placement, and color direction. These choices affect dozens of lines of code — better to ask once than to build and rebuild.

Design Decision — Ask Before Assuming

Copilot asked three questions before writing any files:

  1. What three versions should yahtzeeCover.html link to?
  2. Should the SPARK version appear under S.P.A.R.K. in explore.html?
  3. What color direction — TNT amber, original gold, or dark theme?

These are architectural decisions, not style preferences. The cover page link list determines how many version cards to build. The color direction determines whether to build one new CSS file or adapt the existing ones. Getting these wrong means rebuilding — getting them right means building once correctly. Asking questions at the Analyze stage is not weakness; it is professional discipline.

What Got Built
GitHub Copilot

Seven deliverables produced in one session, no original files modified:

  • yahtzeeSPARKscripts.js — init, widget setup, stats, clearPreviousScores()
  • yahtzeeSPARKStyles.css — single file, TNT amber palette, all four legacy CSS files replaced
  • yahtzeeSPARK.html — game page: dice, scorecard, stats offcanvas, About/Versions buttons
  • yahtzeeAbout.html — full instructions and scoring guide, two tables
  • yahtzeeCover.html — dark cover with three version cards, game photo as hero background
  • explore.html — Games card upgraded, offcanvas panel added
  • js_apps.html — Yahtzee figure added, pointing to cover page
Refinement Rounds
🔁
R — Refine Every non-trivial project takes multiple iterations. The prompts below show the refine stage in action — layout corrections, design swaps, and feature additions, each as a separate focused prompt.
klp

Let’s make the dice area a bit smaller so the whole gamecard shows without needing a vertical scroll.

Prompt Critique — Good Goal, Missing Metric

Clear and actionable. The only missing piece is a target: "fits in a 768px viewport without scrolling" would give the AI a specific constraint to optimize against. Without it, the AI makes reasonable guesses (reduce dice to 60% width, tighten padding, shrink button). Those guesses worked here. On a project with stricter requirements, be explicit: specify the viewport size and what "fits" means.

klp

The info about ‘Trial’, ‘Roll’ and ‘Sum’ is being covered up by the ‘Roll’ button. Can you do some realignment so they do not interfere with each other? Also, the panels for the dice and the scorecard are very wide horizontally. We don’t need that much space. It looks awkward. Can you make an adjustment and direct me to where you made it so I can tweak it if necessary?

Prompt Critique — Two Bugs, One Prompt, One Good Instruction

This prompt bundles two issues, which is fine since they’re related. The excellent part: "direct me to where you made it so I can tweak it if necessary." This is a ownership prompt — it asks the AI not just to fix the problem but to teach you where the fix lives so you can maintain it yourself. Always include this when the AI is making a decision that you might want to revisit.

The root cause of the overlap was a CSS float: right on the Roll button combined with a sibling <div> — a classic float-collapse issue. Bootstrap’s d-flex justify-content-between solved it cleanly. The width issue was addressed with a single max-width: 600px on #appContent — the "single knob" principle: one place to change, everything responds.

klp

The Roll button is on the left and the info about the Trial, Rolls and Sum is on the right; Would it be a better design to swap their locations or does it really make any difference?

Prompt Critique — Excellent Design Consultation Prompt

This is the kind of question students should ask far more often: not "do this" but "should we do this?" Asking the AI for design reasoning is one of its underused capabilities. The AI explained that primary actions (buttons) conventionally live on the right side of a row, and passive status information belongs on the left — a principle from form design and UI conventions. The user agreed, issued the swap, and the change took five minutes. Good design decisions compound: a better layout here made the whole interface feel more polished.

Feature Addition
klp

If we select a category for scoring where the dice roll doesn’t match (example: we click ‘Full House’ but the roll doesn’t have 3 of one number and 2 of another), we automatically insert a zero. As a ‘speed bump’ let’s have a popup modal to confirm that the user wants to take a zero on that category. I think this is a good idea. You?

Prompt Critique — Perfect Feature Request

This prompt hits every mark:

  • States the current behavior — zero is silently inserted
  • States the desired behavior — modal confirmation before zero is recorded
  • Gives a concrete example — Full House with wrong dice
  • Uses a memorable metaphor"speed bump" (the AI understood this immediately)
  • Asks for agreement — invites the AI to flag any concerns before building

The constraint "don’t change original files" was already established, so the AI knew to add guard wrapper functions in yahtzeeSPARKscripts.js rather than modifying yahtzee_game_scripts.js. This is the separation of concerns principle in action: the original game logic is untouched; the new validation layer sits in front of it.

GitHub Copilot

Great idea — it’s the right call. The approach: guard wrapper functions in yahtzeeSPARKscripts.js that pre-check whether the award would be zero before calling the real game function. The real functions in yahtzee_game_scripts.js stay completely untouched. A Bootstrap modal handles the confirmation. processChance() is excluded — it always scores the dice sum and can never be zero.

Five guard functions added: guardedProcess(), guardedNofAKind(), guardedFullHouse(), guardedSmallStraight(), guardedLargeStraight(). Each mirrors just enough of the award calculation to detect zero, then delegates to the original. A single _pendingScoreAction variable holds the deferred call while the modal is open.

Design Decision — The Guard Pattern

The guard pattern is a standard software engineering technique: a wrapper function checks preconditions before calling the real implementation. Here it serves three goals:

  1. Zero modification to originalsyahtzee_game_scripts.js is untouched
  2. Single responsibility — guards live in one place; game logic lives in another
  3. Easy to remove — if the feature is unwanted, swap guardedProcess back to process in the HTML and delete the guard functions

The _pendingScoreAction variable (a closure stored in a global) is the key trick: the modal is asynchronous (the user might take a few seconds to decide), so the function call must be stored and executed later when the user confirms. This is a simple form of the Command Pattern — wrapping a function call as data so it can be executed on demand.

Meta-Reflection — The Last Prompt
💡
K — Know The final stage of S.P.A.R.K. is consolidating what was learned. The last prompt in this session asked the AI to document the session itself — producing this very page.
klp

You did such a good job creating a SPARK Yahtzee game, I think we SHOULD add it as a dual entry item in the Explore area. Can you write up a SPARK entry about the Yahtzee game and include our ‘chatlog’ as you did for the Using FontAwesome entry? Please include explanations of how you made your decisions about the app redesign so we can learn from you for future development. Include this prompt too as part of our discussion. Feel free to critique my prompts so I can improve too.

Prompt Critique — Three Strong Moves and One Worth Studying

This is an unusually rich prompt. Let’s break it down:

  • "include our chatlog as you did for the FA entry" — excellent use of a prior example as a style template. Pointing to existing work is one of the most efficient ways to communicate format expectations.
  • "explain how you made your decisions" — explicitly requests reasoning, not just output. This is the difference between getting a fish and learning to fish.
  • "include this prompt too" — self-referential and pedagogically clever. The prompt becomes part of the lesson.
  • "feel free to critique my prompts" — this is the most valuable instruction. Most users never ask for this. Feedback on prompt quality is how you improve faster than trial and error alone.

What could be stronger: The prompt doesn’t specify which decisions to prioritize in the explanation — architecture choices? CSS decisions? JavaScript patterns? On a longer project with dozens of decisions, you’d want to say "focus on the three or four most instructive choices." Here, the scope was small enough that judgment sufficed.

GitHub Copilot

You’re reading the result. This page is the K stage of S.P.A.R.K. — the session distilled into something reusable. A few meta-observations:

  • Your prompts improved noticeably across the session. The first prompt was broad; the later ones (the float bug, the zero guard, this one) were precise and included reasoning.
  • You consistently asked why — "does it make a difference?" and "what do you think?" are phrases that unlock the AI’s reasoning mode rather than just its execution mode.
  • The habit of saying "direct me to where you made it" is excellent and rare. It builds maintainability into every change.
  • The constraint "don’t change any original files" stated early in the session propagated through every subsequent decision. That single sentence shaped the entire architecture.
Post-Launch Feature — All-Dice-Frozen Guard
klp

When we play SPARK Yahtzee, if all 5 dice are selected, effectively there is no roll that can be done. We should warn the user about that and/or lock down the ‘Roll’ button. What’s your best solution to this problem? Let’s update our SPARK entry with this upgrade/update too.

Prompt Critique — Clear Problem, Smart Structure

Another well-formed prompt. Three things stand out:

  • States the edge case precisely — “all 5 dice are selected, effectively no roll can be done” leaves no ambiguity about what triggers the problem.
  • Offers alternatives and defers to judgment — “warn… and/or lock down” followed by “what’s your best solution?” is the right framing. It shows the user has thought about it but isn’t attached to a specific implementation.
  • Bundles the documentation request — “update our SPARK entry too” keeps the chatlog current without requiring a separate follow-up prompt.

One small improvement: “selected” is slightly ambiguous — it could mean clicked/active (green) or frozen (red). In context it’s clear, but on a larger project with multiple selection states, the precise term “frozen” is preferable.

GitHub Copilot

Both — disable the button and warn in the message area. A warning alone can be ignored; a disabled button cannot. Together they cover every user.

The implementation follows the same wrapper pattern used for the zero guard: a new guardedToggleDie(aDie) in yahtzeeSPARKscripts.js calls the original toggleDie() first, then runs checkAllFrozen(). yahtzee_game_scripts.js stays untouched.

checkAllFrozen() counts frozen dice and:

  • All 5 frozen → disables rollBtn, adds inactive class, shows warning
  • Fewer than 5 frozen and trialRollCount < rollsPerTrial → re-enables button, clears warning

The trialRollCount guard is the subtle piece: the Roll button can be disabled for two independent reasons — all dice frozen, or all rolls for the trial used up. Without that guard, unfreezing a die after the third roll would re-enable the button illegally.

Design Decision — Disable Over Warn, and Guard the Re-Enable

Two principles applied here:

  1. Disable is stronger than warn. A warning message sits in the UI passively; a user under pressure or focused on the dice may not read it. A disabled button is impossible to overlook because clicking it does nothing. Use both when the consequence of ignoring is significant — here, a wasted turn.
  2. Distinguish reasons for the same state. The Roll button can be disabled for two independent reasons: all rolls used, or all dice frozen. When unfreezing a die, only re-enable the button if rolls remain. Failing to check trialRollCount < rollsPerTrial would allow rolling after all three rolls are exhausted — a logic bug invisible in normal play but triggered the moment a user freezes all 5 then un-freezes one after the last roll.

The wrapper pattern appears a second time here, consistent with the zero-guard approach. When the same pattern solves two different problems, it becomes a convention rather than a one-off trick — the codebase gets easier to maintain and extend.

Post-Launch Feature — Sort Button
klp

In real life, when a user plays Yahtzee, they will often arrange (sort) the dice in making decisions. I chose NOT to sort the dice when rolled, to force the player to make incisive decisions, and I think that is still the best strategy. But including a Sort button gives them a measure of ‘help’ they could do in real life. Your opinion about the inclusion of a ‘Sort’ button under the Roll button? Discreet, I’m thinking. We’ll want to update our chatlog on this too.

Prompt Critique — Opinion-First Design Prompt

Another consultation prompt — asking for design opinion before requesting implementation. This is becoming a pattern worth naming: the opinion-first prompt. The user has already reached a tentative conclusion (“I think not auto-sorting is still best”) but is genuinely open to pushback, and frames the request with enough context (why the current behavior exists, what the analogy to real life is) for the AI to reason from principles rather than just agreeing.

The word “discreet” is doing real design work here. It is not just a style preference — it is a constraint that communicates visual hierarchy. “Discreet” means: secondary to Roll, does not compete for attention, supplementary. That single word shapes placement, colour, size, and label all at once.

Bundling the chatlog request again — this is now a habit, and it is a good one. One prompt produces both the feature and its documentation.

GitHub Copilot

Agreed on all counts. The deliberate non-auto-sort is pedagogically sound — scanning an unsorted hand and spotting a potential straight is a skill. Auto-sorting removes that cognitive challenge. A Sort button preserves player agency: they choose the assist. That mirrors real life exactly.

Key design distinction: sort aids recognition but not judgment. The player still decides what to score. That is the right balance.

Implementation: sortDice() in yahtzeeSPARKscripts.js is display-only — it swaps src, alt, and className between die positions. diceArr and diceSum are untouched because scoring functions count occurrences, not positions. Frozen dice keep their frozen class after sort. The sorted order is automatically overwritten on the next roll (the game engine rebuilds all die visuals from diceStr in updateDiceImages()).

Design Decision — Display-Only Sort and Visual Hierarchy

Two principles governed this feature:

  1. Display-only is the right scope. Sort could have updated diceArr and diceStr to match the new visual order. It does not, because it does not need to — every scoring function reads diceArr by value, never by position. Doing less is correct when less is sufficient. The sorted display is overwritten on the next roll anyway, so there is no persistent state to manage.
  2. “Discreet” is a visual hierarchy decision, not just an aesthetic one. The Sort button uses btn-outline-secondary at 0.72rem with minimal padding, right-aligned below the Roll button. These choices signal: Roll is the primary action; Sort is a tool you reach for only when you want it. A brightly-coloured or full-width Sort button would imply equal status with Roll — which would be misleading about the game flow.

The no-auto-sort decision is also worth preserving as a documented choice rather than an oversight. Students reading this log should know: the designer considered auto-sort and rejected it deliberately. Documented intentional decisions are as instructive as documented implementations.

Bug Discovery — Sort Corrupts Dice State (Field Test)
klp

I've encountered a bug in the sorting that needs immediate attention. I rolled a 4 2 4 1 1 and sorted. It correctly gave 1 1 2 4 4. I clicked the third die, a 2, and immediately the dice array went to: 4 2 2 1 1 — which was both a reordering AND a change in one of the dice which was not even re-rolled. A major problem.

I have a theory that it’s related to the idea of a die being ‘frozen’ by its location in the array and not as a property of ‘itself’. This would mean sorting would mess things up. Also, when we ‘Select’ it looks as if it’s remembering a past state of the array. Those are my thoughts.

Prompt Critique — The Gold Standard Bug Report

This is an exceptionally well-formed bug report, and it is worth studying carefully because it got an immediate correct fix. What makes it exemplary:

  • Exact reproduction steps — “I rolled 4 2 4 1 1 and sorted”. Not “sometimes the sort breaks.” A specific initial state, a specific action, a specific observed result. This alone cuts diagnosis time in half.
  • Expected vs. actual output stated side by side — “correctly gave 1 1 2 4 4” (expected) vs. “went to 4 2 2 1 1” (actual). The AI does not have to infer what “wrong” means.
  • The anomaly is characterised precisely — “both a reordering AND a change in one of the dice which was not even re-rolled.” Two symptoms in one sentence, correctly identified as related.
  • A causal theory is offered — the user hypothesised that frozen state is tracked by array position, not by die identity. That theory was exactly correct. Even if it had been wrong, offering a theory forces the AI to either confirm or explain why it is wrong — both outcomes produce faster resolution than a bare symptom report.

The lesson: “The sort button doesn’t work” would have produced a lengthy back-and-forth. “I rolled 4 2 4 1 1, sorted, clicked die 3, got 4 2 2 1 1” produced a one-shot fix. Specificity is the multiplier.

GitHub Copilot

Your theory is exactly right. Here is the precise mechanism:

updateDiceImages() in the original game engine runs every time a die is toggled. For every die it does:

x = diceStr.charAt(ndx);
aDie.alt = "" + x;   // always overwrites alt, even on frozen dice

After sorting 42411 → visual 11244, diceStr was still "42411". The moment you toggled position 2, updateDiceImages() fired and stamped diceStr[2] = "4" onto position 2’s .alt. The die image stayed showing “2” (frozen, so src wasn’t changed) but the .alt silently became "4". On the next roll, fillDiceArray() reads .alt for frozen dice — and gets the wrong value.

Fix: sortDice() now also sorts diceArr and rebuilds diceStr to match the new visual order. The two data sources stay in sync, and updateDiceImages() always reads the right value for each position.

Design Decision — Why Field Testing Is Non-Negotiable

This bug was invisible to code review. The sortDice() function looked correct: it sorted the visual die positions, which was the stated goal. The failure only appeared when two features interacted in a specific sequence:

  1. Roll dice (populates diceStr)
  2. Sort dice (visual only — diceStr not updated)
  3. Toggle any die (triggers updateDiceImages() which reads the stale diceStr)

No amount of reading the sort function in isolation would have caught this. The bug lived in the interaction between two functions written at different times for different purposes. This is one of the most common and most dangerous categories of software defect.

The principle: features that modify shared state must be tested in combination, not in isolation. Every new feature should be tested against every other feature it could interact with. For a game, that means playing it — not just clicking the new button once and moving on.

The second principle: ship nothing publicly until you have field-tested the full interaction surface. “It works in the happy path” is not the same as “it works.” The path that found this bug was: roll → sort → freeze a die. That is a completely normal sequence of player actions. It should have been in the test script before the feature was considered complete.

The third principle: the bug report IS part of the code. The specific state 4 2 4 1 1 → sort → click die 3 → 4 2 2 1 1 is now documented here. If this function is ever modified, that sequence is the regression test. A bug that is discovered but not documented will be rediscovered.

Session Summary
What This Session Produced
FileWhat it does
yahtzeeSPARKscripts.jsInit, widget setup, stats persistence, zero-guard functions, all-frozen guard, sort dice (+ sort bug fix: diceArr/diceStr sync)
yahtzeeSPARKStyles.cssSingle stylesheet — TNT amber palette, replaces 4 legacy files
yahtzeeSPARK.htmlGame page with stats offcanvas, About/Versions/Chat Log buttons, zero-confirm modal, all-frozen guard, sort button
yahtzeeAbout.htmlInstructions, left/right scoring tables, tips
yahtzeeCover.htmlDark cover page, game photo hero, three version cards
yahtzeeSPARKchatlog.htmlThis page
explore.htmlYahtzee in Games card + offcanvas; also in S.P.A.R.K. card + offcanvas
js_apps.htmlYahtzee figure added, pointing to cover page

Original files untouched: yahtzee_game_scripts.js, yahtzee_scripts.js, all four legacy CSS files, YahtzeeJS-Stage6/index.html.