Twelve Days of Christmas
Parody — S.P.A.R.K. Chat Log
How a 250-year-old cumulative carol became a five-genre array-driven JavaScript app with a cross-curricular programming lesson hidden inside it.
This log documents the design and build of the Twelve Days of Christmas Parody Sing-Along — a JavaScript app that renders five genre versions of the same cumulative carol from a single array-driven data structure. Two genres (Web/HTML·CSS·JS and Java) were supplied complete; three (Traditional, Python, Mathematics) were designed by the team.
Watch for S.P.A.R.K. banners framing each phase, decision boxes explaining each design choice, and lyric cards showing the completed verses side by side. The core lesson: when multiple outputs share the same structure, a data array plus one rendering function beats five separate HTML pages every time.
I have a song parody featured in mamasFunctionHome and its associated chatlog. I’d like to build a similar song parody of 12 Days of Christmas where we feature versions: traditional, web programming, Java programming, Python programming and mathematics. I’ve got versions for web programming and Java programming. I’m sure you have the ‘traditional’ lyrics. Let’s call it twelveDaysParodySPARK.html along with twelveDaysParodySPARKStyles.css and twelveDaysParodySPARKScripts.js. Rather than having several different pages, let’s populate the song based on the user’s choices using arrays of data sets. A user selects a genre and then subsequent button clicks reveal the song. Once a song genre is selected, the menu should be ‘frozen’ until the song ends or unless the novice ‘Restart’s the process. Let’s build out the versions we have with placeholders for the Python and mathematics versions.
Here’s the web version: A Node in a web page DOM tree / 2 nav bar links / 3 google fonts / 4 nested lists / 5 inline styles / 6 semantic tags / 7 meta statements / 8 chrome extensions / 9 CDNs / 10 stylish icons / 11 image tags / 12 indention levels. Here’s the Java version: On the first week of Java my teacher to us showed: / A class housing main driver code / 2 curly braces / 3 for loops … Notice the opening phrase for Java is different to make it rhyme with first day.
The phrase “rather than having several different pages, let’s populate the song based on the user’s choices using arrays of data sets” is the architectural decision of the entire app. It mandates a single rendering function driven by data rather than duplicated HTML — which is exactly the correct approach when five versions share one structure. The prompt is implicitly teaching the principle it is asking the app to demonstrate.
The Java opening phrase note — “Notice the opening phrase for Java is different to make it rhyme” — is a precision detail that would have been lost if the user had not flagged it explicitly. Each genre in the GENRES object carries its own openingTemplate string, which handles this variation without any special-casing in the rendering function. The data structure accommodates variation naturally.
Specifying “freeze the menu until the song ends or until Restart” defines the exact UI state machine: selected → frozen → reset. This is more precise than “disable the other buttons” — it implies that the selected button should remain visually present and that Restart (not End of Song alone) is the path back to menu interaction.
- A partridge in a pear tree
- Two turtle doves
- Three French hens
- Four calling birds
- Five golden rings!
- Six geese a-laying
- Seven swans a-swimming
- Eight maids a-milking
- Nine ladies dancing
- Ten lords a-leaping
- Eleven pipers piping
- Twelve drummers drumming
- A Node in a web page DOM tree
- 2 nav bar links
- 3 Google Fonts
- 4 nested lists
- 5 inline styles!
- 6 semantic tags
- 7 meta statements
- 8 Chrome extensions
- 9 CDNs
- 10 stylish icons
- 11 image tags
- 12 indention levels
Opens with “week” + “showed” to rhyme
- A class housing main driver code
- 2 curly braces
- 3 for loops
- 4 static methods
- 5 data types!
- 6 constructor calls
- 7 thrown exceptions
- 8 utilities
- 9 private ivars
- 10 setter methods
- 11 semicolons
- 12 recursive statements
- A print statement in a .py file
- 2 list comprehensions
- 3 lambda functions
- 4 dictionary keys
- 5 data types!
- 6 module imports
- 7 virtual environments
- 8 class methods
- 9 generator expressions
- 10 decorators
- 11 f-strings
- 12 Pythonic ways
- A root of a quadratic equation
- 2 rational roots
- 3 trig identities
- 4 ordered pairs
- 5 golden ratios!
- 6 sigma sums
- 7 transformations
- 8 matrix rows
- 9 eigenvalues
- 10 derivatives
- 11 infinite limits
- 12 complex numbers
GENRES Object, One RendererThe core data structure is a single GENRES object with one key per genre. Each genre entry contains its name, emoji, openingTemplate string (with {ordinal} placeholder), a placeholder boolean, and a 12-element gifts array. Each gift object has a text property and an optional andText (the refrain form) and special boolean.
The renderVerse(day) function reads the selected genre from this object and builds the verse entirely from data. Adding a sixth genre (e.g., “Computer Science AP”) requires only a new entry in GENRES and a new button in the HTML. Zero changes to the rendering logic or CSS.
In the traditional carol, day 1’s gift appears as “A partridge in a pear tree” in verse 1, but becomes “And a partridge in a pear tree” in verses 2 through 12. This is the standard performance convention. Each genre’s day-1 gift therefore has two forms stored: text (verse 1) and andText (verses 2–12).
// In renderVerse(), the choice is made at render time:
if (d === 1 && day > 1) {
text = giftData.andText || ('And ' + lcFirst(giftData.text));
} else {
text = giftData.text;
}
The lcFirst() fallback lower-cases the first character, so even if andText is not supplied, “A partridge” becomes “And a partridge” cleanly. All five genres supply explicit andText values for their day-1 gift.
Three states govern the genre menu:
- Idle — all five genre buttons enabled, no song in progress, Restart disabled.
- Singing — selected genre button highlighted, all other buttons disabled (dimmed to 30% opacity), Restart enabled. Next Verse reveals days 1–12 one at a time.
- Complete — all 12 days revealed, Next Verse button hidden, “All twelve days complete” banner shown. Restart (or the “Sing Again” button in the banner) returns to Idle.
The onGenreSelect(), onNextVerse(), and onRestart() functions manage these state transitions. The selectedGenreId variable (null = Idle, string = Singing/Complete) is the single source of truth for which state the app is in.
In the traditional carol, the fifth day’s gift (“Five golden rings!”) is traditionally sung with extra emphasis — a held note, a key change, a dramatic pause. Every genre preserves this as a design convention: day 5’s gift carries special: true, which the renderer marks with the gift-item--special CSS class (gold color, bold, italic). This gives each genre its own equivalent “golden rings” moment: 5 inline styles!, 5 data types!, 5 golden ratios!.
The convention also serves a pedagogical purpose: the surprise and emphasis of the traditional carol’s fifth gift is intentionally preserved, reminding students that musical structure and code structure share the same device — a pattern with a deliberate disruption.
The Twelve Days of Christmas is already the anchor app for Cross Training Concept #4: Conditional Logic — The Switch & Cascade. The concept page demonstrates that the cumulative verse structure (enter at day 12, fall through to day 11, 10… down to 1) is a natural model for a switch statement with deliberate fall-through — the language feature most beginners are warned against.
A Cross Training showcase section was added to the bottom of the app page to surface this connection. Students who use the parody app see the song as a fun classroom artifact; the showcase invites them to discover that the song’s structure has a name in computer science: the cascade.
| File | Status | What it contains |
|---|---|---|
twelveDaysParodySPARK.html |
New | TNT navbar, SPARK bar (chatlog + movie clips + Cross Training links), Christmas hero, genre selector (5 buttons), song section (verse display + controls + progress dots), Cross Training showcase, TNT footer. |
styles/twelveDaysParodySPARKStyles.css |
New | Christmas color palette (red, green, gold, cream). Hero overlay. Genre button states (idle, selected, inactive). Song section (dark green gradient). Progress dots. Verse/gift list styles including gift-item--current (gold highlight) and gift-item--special (bold gold). Cross Training showcase card. |
scripts/twelveDaysParodySPARKScripts.js |
New | GENRES object with all five genre datasets. ORDINALS array. setup(), onGenreSelect(), onNextVerse(), renderVerse(), onRestart(). Progress dot builder/updater. init() for copyright and validateLink. |
twelveDaysParodySPARKChatlog.html |
New | This document. |
The naive approach to this app would be five separate HTML pages, one per genre. The app would “work,” but:
- Any change to the verse-reveal logic would require five edits in five files.
- Any change to the page layout would require five edits.
- Adding a sixth genre would require creating a sixth file.
- A bug in the day-1 refrain logic would need to be found and fixed five times.
The data-driven approach inverts every one of those problems: logic is in one place, layout is in one place, adding a genre is one object entry, and fixing a bug is one fix. This is the JavaScript equivalent of the database normalization principle — store each fact once and derive everything else from it.
The student lesson: whenever you find yourself copy-pasting a block of HTML or JavaScript and changing only the data inside it, that is the signal to extract the data into an array or object and write one parameterized function. The parody app is a live demonstration of this principle using content students already know.
openingTemplate PatternEach genre’s opening line differs in two ways: the context word (“day of Christmas” vs. “week of Java”) and the verb phrase (“my true love gave to me” vs. “my teacher to us showed”). Rather than writing a function with five if branches, each genre stores a complete template string with a single {ordinal} placeholder:
// Java genre
openingTemplate: 'On the {ordinal} week of Java, my teacher to us showed:',
// The renderer substitutes the ordinal at runtime:
var opening = genre.openingTemplate.replace('{ordinal}', ORDINALS[day - 1]);
This pattern — store the variant as data, substitute at runtime — generalizes to any content that varies by parameter. It is the core of template engines, i18n systems, and parametric SQL queries. The parody app uses it in its simplest possible form, which makes it an ideal first exposure to the concept.
The Cross Training concept pages use a mini-nav bar immediately below the main navbar: a dark #0a0e1a banner with a colored bottom border, left-aligned links in gold (primary) and semi-transparent white (secondary), and a right-aligned faded page label. The pattern uses inline styles so it is self-contained and requires no external CSS class.
The SPARK bar on the parody page and the back bar on this chatlog were updated to match that same structure. The border-bottom accent uses Christmas red (#C41E3A) instead of the Cross Training holly green, so each section keeps its thematic color while sharing the same layout.
Takeaway: visual consistency across companion pages — app, chatlog, concept page — reinforces the relationships between them. When the navigation chrome speaks the same design language everywhere, users move through the set with less friction.
With the app, chatlog, movie clips page, and Cross Training page all updated, the final step is wiring the app into the site-wide discovery pages: news.html (entry #066, positioned above the Parabola Saga as the most recent 2026 entry) and explore.html (three offcanvas panels).
The news entry summarizes the array-driven architecture, the five genres, and the Cross Training connection, and provides direct links to the app, this chatlog, the movie clips page, and the Cross Training concept page — the same four-corner link set used at the bottom of each companion page.
For the Explore page, the app was classified in three panels:
- S.P.A.R.K. — Both the app and this chatlog are listed here, consistent with the pattern for all SPARK projects. The chatlog is listed only in the SPARK panel; the other panels link to the app alone.
- Text-Based — The app’s primary output is structured text (song lyrics) assembled from JavaScript data arrays. There is no canvas, no physics, no graphics — it is fundamentally a text-generation and display problem. Text-Based is the right home.
- Miscellaneous — The app is a seasonal song-and-parody classroom utility. Its closest sibling in the site is Vibe Codin’ (a Bee Gees parody), which is already in Miscellaneous. The app’s educational value comes from its Cross Training connection, not from being a standalone CS tool, so Misc is the correct secondary classification rather than a more specific category.
All three classifications will appear in the offcanvas panels only; the featured cards on the Explore page main view already have five entries each.