Back to Magic 8 Ball SPARK Edition S.P.A.R.K. Chat Log  •  07/06/2026
S.P.A.R.K. with AI — Development Dialog

Building the Magic 8 Ball SPARK Edition

From a Stage 6 legacy app to a fully integrated TNT simulation —
the sphere algorithm, the probability system, and the design decisions.

For Students — How to Read This Page

This log documents the session that refactored the Stage 6 Magic 8 Ball app into the 2026 SPARK Edition. Unlike the Slot Machine refactor — where the primary challenge was redesigning the visual shell — this session had two equally important goals: the visual upgrade and understanding the mathematics already inside the app.

Watch for Prompt Critique boxes (amber) and Design Decision boxes (teal). The most important teaching moments here are not about web design — they are about the sphere shading algorithm and the probability system that the original developer built.

🎯
S — Set Goal The session began with an analysis request, not a build request. The AI read every file and assessed the app before a single line was changed.
klp

I have another app, magicEightBallIndex.html (with accompanying support files) that works well and validates, but it doesn’t have the ‘look and feel’ of our new TNT upgrades. Before we do any work, I’d like you to scan that 8ball app and see if you think it is worth the effort to upgrade. Part of me thinks the apps in Processing should be somewhat uniform, but there could be value in students seeing different designs. As a professional educator, design specialist and web design specialist, lets look at the pros and cons of making an additional magic8ball app.

Prompt Critique — Three Requests in One Well-Organised Prompt

This opening prompt accomplishes three things cleanly:

  1. Frames the current state — “works well and validates” signals that the scripts should not be touched. Only the presentation needs work.
  2. Requests analysis before action — “before we do any work” is the most important phrase. It prevents the AI from starting to build before the context is understood.
  3. Raises a genuine design question — “uniform vs diverse” is a real pedagogical tension, not a rhetorical one. Naming it invites a substantive answer.

The role-framing (“as a professional educator, design specialist and web design specialist”) is effective because it asks for multi-perspective analysis. Different professional lenses produce different answers: an educator values comparing old and new; a designer values visual consistency; a web specialist flags technical debt. Asking for all three perspectives in one prompt is efficient.

GitHub Copilot

After reading all files, here is what the app contains and what the upgrade involves:

What the scripts do (zero changes needed):

  • magic8BallSketch.js — a sophisticated p5.js sketch featuring a 50-layer gradient sphere, randomised shine-spot geometry, angle-clamped text rotation, and a fade-in animation.
  • m8ballResponses.js — four probability-weighted response arrays (positive 35%, negative 35%, vague 20%, snarky 10%) with a clean cumulative-range selection algorithm.

What the HTML/CSS need (new shell only):

  • Full TNT 2026 navbar and footer
  • Hero section with the firefly background image
  • <details>/<summary> About section
  • New magic8BallSparkStyles.css (deep purple-black palette)
  • The “Behind the Scenes” debug panel redesigned as a student-facing “Math Behind the Ball” educational panel
  • p5.js bumped from 1.6.0 to 1.9.0
  • linkGuard.js added

Uniform vs diverse: Uniformity should live at the ecosystem level (navbar, footer, hero structure, CSS custom properties). Diversity should live at the app level. The sphere interaction — click, no sliders, full-canvas — is genuinely different from the Slot Machine. That difference is worth preserving and showing side-by-side.

Design Decision — The Uniform / Diverse Balance

The apparent tension between “uniform” and “diverse” dissolves when you define what should be uniform and what should be diverse:

  • Uniform: the frame. Navbar, footer, hero typography, CSS custom properties, link patterns. A student arriving at any TNT Processing app should immediately recognise the ecosystem. Navigation should feel identical across all apps.
  • Diverse: the content. The Slot Machine has two columns and a controls panel because it has controls. The Magic 8 Ball has no controls — the only interaction is a click. A two-column layout with an empty right column would be visual noise. Single-column centred is the correct layout for this app.

The deeper pedagogical point: showing students different layouts within the same visual ecosystem demonstrates that design responds to content requirements, not the other way around. “Use the same layout as the last app” is not a design principle — it is laziness. “Use the layout that fits the content” is.

The File Structure Decision
💬
P — Prompt The second prompt resolved the architecture of the refactor with a single, well-considered instruction about file structure.
klp

I’m thinking we keep the original files and include in the 8ball folder a magicEightBallSparkIndex.html and in its styles folder a magicEightBallSparkStyles.css. From what I gather, those are the only new files we need. For comparison and contrast, we can link the old look files to the new ones so students can learn by seeing the differences. Of course, we will need a magicEightBallChatlog.html. Let’s use the pattern we’ve used in other SPARK applications. Let’s include your suggestions about the sphere algorithm and the probability system.

Prompt Critique — File Names as Architecture

The instruction to name the new file magicEightBallSparkIndex.html rather than, say, index2.html or indexNew.html is a meaningful architectural decision. The name:

  • Identifies the project (magicEightBall)
  • Identifies the version type (Spark)
  • Identifies the role (Index)

A student navigating the folder sees two files: magicEightBallIndex.html and magicEightBallSparkIndex.html. The relationship between them is self-documenting. No README needed.

The instruction to “link the old look to the new ones so students can learn by seeing the differences” is a pedagogical pattern worth formalising. When a refactor preserves the original, the two versions together have more educational value than either alone. The SPARK version teaches web standards; the original teaches the evolution of design practices.

GitHub Copilot

Confirmed. Three new files only; all original files untouched:

  • magicEightBallSparkIndex.html — new TNT shell, same two scripts
  • styles/magic8BallSparkStyles.css — deep purple-black palette
  • magicEightBallChatlog.html — this page

The scripts m8ballResponses.js and magic8BallSketch.js are loaded unchanged by both the original and the SPARK version — same principle as Reel.js in the Slot Machine refactor.

Design Decision — Preserve Working Code; Build a New Shell Around It

Both the Slot Machine and the Magic 8 Ball refactors follow the same pattern:

  1. Read all existing files before writing anything
  2. Identify which files are working and well-written (the scripts)
  3. Mark those files as untouchable
  4. Build the new presentation layer around them

This is not conservatism — it is risk management. Working, tested code is an asset. Rewriting it to fit a new aesthetic introduces the possibility of new bugs in logic that was already proven. The Slot Machine’s Reel.js survived unchanged. The 8 Ball’s sphere algorithm and probability system survive unchanged. In both cases, the constraint produced better outcomes than a full rewrite would have.

Teaching Moment — The Sphere Shading Algorithm
🔍
A — Analyze Two algorithms in the original app are worth examining closely as teaching content. The first is the sphere itself — a 3D illusion built from fifty flat circles.
GitHub Copilot

The sphere is drawn in draw8Ball() with a loop that runs exactly 50 times. Here is what each iteration does:

for(var i = 1; i <= numLayers; i++){
    xc   = map(i, 1, numLayers, 0, xs);
    yc   = map(i, 1, numLayers, 0, ys);
    myDiam = map(i, 1, numLayers, ballDiam, shineDiam);
    // colour interpolates black → medium-gray
    fill(color(myH, myS, myB));
    circle(xc, yc, myDiam);
}

Three things are happening simultaneously on each step:

  1. The centre moves. It starts at (0,0) — the ball’s centre — and shifts toward (xs, ys), the randomised shine spot position. map() does this proportionally.
  2. The diameter shrinks. It starts at ballDiam (the full ball) and ends at shineDiam (half the ball). Smaller circle, closer to the highlight.
  3. The colour brightens. HSB colour mode lets the code interpolate hue, saturation, and brightness independently from black to medium gray — the visual signature of a light source.

The result: 50 concentric circles, each one slightly smaller, shifted, and lighter. Because each circle completely covers those behind it except at the edges, what you see is a smooth gradient that your visual system interprets as a curved 3D surface. No 3D engine. No normals or vectors. Just map().

Design Decision — Simplified Phong Shading Without the Math

In computer graphics, Phong shading is a standard technique for making 3D surfaces look lit. The full algorithm involves calculating surface normals, a light direction vector, and a reflection model. It produces beautiful results but requires linear algebra.

The Magic 8 Ball sketch achieves a visually convincing approximation using nothing but map(). The key insight is that all three interpolations (position, size, colour) run on the same parameter i, which means they stay perfectly coordinated without any vector math.

This is excellent pedagogical code for two reasons. First, it demonstrates that visual complexity does not require mathematical complexity — a well-chosen loop structure is enough. Second, it uses map() for three different purposes in the same loop, which shows students the versatility of a function they may have assumed was only for slider rescaling.

Teaching Moment — Weighted Random Selection
GitHub Copilot

The response system in chooseMessageType() is a textbook implementation of weighted random selection. The logic is:

var cutoff1 = probPos;                    // 0.35
var cutoff2 = cutoff1 + probNeg;          // 0.70
var cutoff3 = cutoff2 + probVague;        // 0.90
// snarky: the remaining range 0.90 → 1.00

if      (rn <= cutoff1) { targetArray = positiveMsgs; }
else if (rn <= cutoff2) { targetArray = negativeMsgs; }
else if (rn <= cutoff3) { targetArray = vagueMsgs; }
else                    { targetArray = snarkyMsgs; }

A single Math.random() call produces a uniform value in [0, 1]. The code partitions that range into four segments sized proportionally to the desired probability. Land in [0–0.35] and you get a positive response. Land in [0.35–0.70] and you get negative. And so on.

This technique has a formal name: inverse transform sampling, or CDF (Cumulative Distribution Function) sampling. The “cumulative” part is exactly what the cutoff variables represent — each cutoff is the sum of all probabilities up to that point.

Design Decision — From Gambling to Machine Learning: The Same Algorithm

CDF sampling is not a toy algorithm. Here is where students will encounter the same pattern at increasing levels of sophistication:

  • Games. Loot tables, enemy spawn rates, and random weather systems all use weighted distributions. A sword drops 5% of the time; a coin drops 60% of the time. The code structure is identical to the 8 Ball.
  • Simulations. The Slot Machine in this same TNT collection models probability through reels. The 8 Ball models it through response weights. Both are discrete probability distributions implemented as CDF ranges.
  • Machine learning. Temperature-scaled sampling in language models, nucleus sampling, and beam search all involve selecting from a weighted probability distribution over a vocabulary of possible next tokens. The underlying mechanism is the same: divide [0,1] into segments, sample uniformly, land in a segment.

The Magic 8 Ball teaches this concept in the most approachable possible context — a toy. The stakes are imaginary. The math is real. When a student later encounters softmax sampling in a deep learning course, they have already seen the idea.

Refinement — From Debug Tool to Educational Panel
✏️
R — Refine The original app had a “Behind the scenes” panel that displayed raw geometry values. The SPARK Edition transforms it into a student-facing educational tool.
GitHub Copilot

The original resultsDiv panel shows values like:

ballRadius = 180
shineRadius = 94.3
shineAngle (deg) = 137.2
viewPort Locn: (−67.4, 72.1)
viewPortRadius = 50
myRotnDeg = −42.8
messageType = snarky
numChars = 22
fontSize = 18.4

This was written as a developer debug output. In the SPARK Edition it becomes The Math Behind the Ball — exactly the same data, but framed as insight into the algorithm rather than a debug dump. No code change required. Only a CSS treatment and a new label.

Design Decision — Developer Transparency as Pedagogy

The original developer left the debug panel visible (collapsed by default). This was likely done to understand the sketch during development and then never removed. In the SPARK Edition, that “accident” becomes intentional policy.

Each field in the panel corresponds to a meaningful algorithm step:

  • shineRadius and shineAngle — where the 50-circle gradient aims its highlight. Students can try to predict the visual from the angle value.
  • viewPort Locn — the centre of the dark circle that frames the response text. This is the final resting position of the innermost of the 50 gradient circles.
  • myRotnDeg — how many degrees the text is tilted. The angle is clamped to ±50° so the text never becomes unreadable, regardless of where the shine spot lands.
  • fontSize — the computed size from the formula 0.75 × viewPortDiam / √numChars. Students can verify that longer messages produce smaller text.

The pattern to generalise: developer debug output is a liability in production code but an asset in educational code. When writing apps for teaching, leave the debug window — just style it so it is clearly optional rather than broken.

Technical Detail — Script Loading and Font Dependencies
GitHub Copilot

Two subtle dependencies in magic8BallSketch.js shaped the SPARK HTML structure.

1. DOM references at global scope. The very first lines of the script (outside any function) are:

var contentDiv  = document.getElementById("primaryContent");
var loadingPara = document.getElementById("loadingPara");
var resultsPara = document.getElementById("resultsPara");
var resultsDiv  = document.getElementById("resultsDiv");
var askPara     = document.getElementById("askPara");

These run the moment the script file loads. All five element IDs must exist in the HTML before the script tag is reached. This is why all app scripts are at the bottom of <body>, not in <head>.

2. The Henny Penny font. setup() calls textFont("Henny Penny"). p5.js draws text using the browser’s font rendering — it looks up the font name in the CSS font registry. If “Henny Penny” is not loaded in the HTML via a <link> to Google Fonts, the canvas falls back silently to a default serif font. The font is not used anywhere in the HTML; it exists solely for the canvas. The Google Fonts import must stay even though no HTML element references it.

Design Decision — Two Ways a Font Can Be “Needed”

This app demonstrates that a Google Font can be required for two distinct reasons:

  • CSS font: Used in the HTML via font-family rules. If the import is missing, the fallback font appears in the page text.
  • Canvas font: Used in the sketch via textFont("name"). If the import is missing, the canvas falls back silently — no error, just the wrong typeface on the ball.

Both require the <link> tag in <head>. The difference is that the canvas failure is harder to diagnose because there is no console error. When a p5.js sketch uses a specific font and the rendering looks wrong, the first thing to check is whether that font is in the Google Fonts import. The comment in the SPARK HTML documents this explicitly so the next person who reads the file understands why a font with no visible HTML usage is still required.

💡
K — Know Four principles from this session to carry into every future p5.js project and every future refactoring task.
Session Takeaways
  1. Three circles of p5.js knowledge. (1) Drawing primitivescircle(), rect(), line(). (2) Coordinate transformstranslate(), rotate(), scale(), push()/pop(). (3) The map() function — the single most versatile tool in p5.js, able to drive position, size, colour, and opacity simultaneously from the same loop variable. Master these three and you can build the sphere algorithm.
  2. Math.random() is a starting point, not a solution. Uniform randomness produces equal probability for every outcome. Almost no real simulation wants that. The CDF partition pattern — define cumulative cutoffs, compare a single random value — converts uniform randomness into any weighted distribution you need. The 8 Ball uses it for response types. Games use it for loot. ML uses it for token sampling. It is the same algorithm.
  3. Leave the debug panel; style it properly. In production code, debug output is removed. In educational code, debug output is a feature — it makes the algorithm visible. The difference is in the framing. “Behind the scenes” reads as broken; “The Math Behind the Ball” reads as intentional. The code is identical. The label changes everything.
  4. Fonts on canvas require explicit HTML imports. A font used only in a p5.js sketch via textFont() still needs a Google Fonts <link> in the HTML. The canvas looks up the font by name in the browser’s CSS registry. If the import is missing, the failure is silent. Comment the import to explain why it is there.
What This Refactor Produced
FileStatusWhat it does
scripts/m8ballResponses.jsUnchangedFour probability-weighted response arrays
scripts/magic8BallSketch.jsUnchanged50-layer sphere, fade animation, font scaling
magicEightBallIndex.htmlUnchangedOriginal Stage 6 — preserved for comparison
styles/siteStyles.cssUnchangedOriginal styles — preserved for comparison
magicEightBallSparkIndex.htmlNewFull TNT navbar/footer, dark hero, single-column layout
styles/magic8BallSparkStyles.cssNewDeep violet-black palette; TNT amber accents
magicEightBallChatlog.htmlNewThis page

Original Stage 6 preserved untouched. Both versions share the same two script files — one codebase, two presentations.

Post-Session — The Hero Icon: Font Awesome vs. Project PNG
klp

The icon in front of the heading in the hero area is just a circle. Is there an 8ball icon in Font Awesome? I have a png of an actual 8 ball we could use. I think that would be more effective visually than a plain circle. Your take?

Prompt Critique — Tool-Choice Question Done Right, Again

This prompt follows the same pattern as the Slot Machine’s “FA icons or noun-project icons?” question — asking which tool to use before committing to either. The user suspected Font Awesome might have an 8-ball but wasn’t sure; asking first took one sentence. If the answer had been “yes, use fa-8-ball” the conversation would have ended in thirty seconds. If the answer was “no” — which it was — the question prevented an implementation that would have needed to be unwound.

Note also the framing: “I think that would be more effective visually than a plain circle.” This is a design opinion stated as an opinion, not a requirement. It invites agreement or disagreement rather than just execution. That openness led to a better answer than a directive would have.

GitHub Copilot

Font Awesome 6.5 free has no 8-ball icon. The closest free options are fa-bowling-ball (a plain dark sphere with no “8”) and fa-circle — which is exactly what you already have. Any meaningful billiard/pool icon requires the Pro tier.

The noun-project file noun-8-ball-6262.png is already in the app’s images/ folder. It is the same image used as the navbar icon in the original magicEightBallIndex.html. Using it in the hero creates visual continuity between the two versions and is far more distinctive than any generic circle.

Implementation: replace the <i> with an <img> sized at height:0.85em so it scales with the hero heading text.

klp

The 8ball image is a png and it needs a white background underlay to be visible on the dark hero background. Can you provide that?

GitHub Copilot

The original app already solved this problem for the navbar icon. The CSS was background-color: white; border-radius: 50%; padding: 1px. The same three properties applied inline to the hero <img>:

style="height:0.85em; width:auto; vertical-align:middle;
       background-color:white; border-radius:50%; padding:2px;"

The border-radius:50% clips the white rectangle to a circle so no white corners bleed out at the corners of the image. The padding:2px gives a hairline white halo that separates the black ball edge from the dark hero background — the same visual effect as the original navbar icon.

Design Decision — Project Assets Create Brand Continuity

Using noun-8-ball-6262.png in the hero rather than a Font Awesome substitute is a branding decision, not just a technical one. The image appears in two places in the Magic 8 Ball experience:

  • Original app navbar — as the masthead icon, white circle background, border-radius 50%
  • SPARK Edition hero heading — same image, same treatment, scaled to match heading text height

A student moving between the two versions sees the same icon in both. That continuity signals “same app, different presentation” without requiring any text explanation. Icons used consistently across versions of the same product function as a brand mark — even in a teaching context.

The broader principle: when a project already has a distinctive asset, use it consistently rather than substituting a generic alternative. Font Awesome provides excellent generic icons. It cannot provide this project’s icon.

Post-Session — Cross-Listing on Explore & Processing Pages
klp

In the processing and explore pages, we need to link to our improved SPARK magic 8 ball app. Also, on the explore page, we need to include it as a SPARK type app as well since we showcase work you do there. Let’s add these additions to our chatlog too since they are part of the development process.

Prompt Critique — Documentation as Part of Development

The instruction to add cross-listing changes to the chatlog — not just to the HTML files — reflects a mature view of what a development log is for. A chatlog that stops at “files created” and omits “files registered in the ecosystem” tells an incomplete story. The act of listing an app in the navigation is a development step, not a clerical afterthought.

This also applies the cross-listing convention that was established in the Slot Machine chatlog: an app with a SPARK chat log belongs in the S.P.A.R.K. category, its technology category (Processing), and its content category (Simulations) — each for a different reason, with different student audiences in mind. Following the convention consistently is what makes a convention useful.

GitHub Copilot

Three files updated; all links now point to the SPARK Edition:

  • explore.html — S.P.A.R.K. card: Magic 8 Ball SPARK added to the featured list. Simulations card and Processing card: links updated from original to SPARK Edition. S.P.A.R.K. offcanvas, Processing offcanvas, and Simulations offcanvas: each gains a SPARK Edition entry and a Chat Log entry.
  • processing_apps.html — The Magic 8 Ball figure href updated from magicEightBallIndex.html to magicEightBallSparkIndex.html; figcaption updated from “p5.js simulation” to “SPARK Edition”.
  • magicEightBallChatlog.html — This entry.

The original magicEightBallIndex.html remains accessible from the SPARK Edition’s “Original Version” link. The ecosystem pages surface the best version; the comparison path is one click away.

Design Decision — Ecosystem Pages Should Surface the Best Version

When a SPARK Edition exists, the cards and offcanvas panels on explore.html and processing_apps.html should link to it, not to the original. The reasoning:

  • A student navigating the ecosystem pages is looking for something to use or learn from. The SPARK Edition is the better version on both counts.
  • The original is not lost — it is one click away from the SPARK Edition’s “Original Version” link. The comparison is still fully available.
  • Pointing the grid to the original while a SPARK Edition exists creates a silent inconsistency: the site appears to not know its own best work.

The rule: ecosystem pages point to the current best version. The current best version links back to the original. Students who want to compare will find the path; students who just want to use the app get the best one immediately.