Lab · Codegen study
35 holidays in 4 weeks
A small YAML file, a calendar engine, and a sprite sheet full of tiny props.
Published
~1 min read · 499 words
On this page
Four was not enough
The original screensaver had four holiday decorations: Halloween, St. Patrick’s Day, Christmas, and New Year. They are charming because they are small. A pumpkin. A tree. A banner. A few clovers. Not a reskin. Not a special mode. Just the island noticing the calendar.
The PS1 port keeps those four exactly as they were. Then it adds more.
The final table at this release has 36 holidays, including 4/20 Day because the user asked for it directly and it made the sheet better. Fixed dates, movable Sundays, Nth weekday rules, Easter-relative holidays, solstices, Election Day. A tiny calendar engine hiding behind a tiny beach.
The source of truth
The source file is holidays.yml.
That file names each holiday, its short label, date rule, sprite dimensions,
anchor, palette hints, and description. Codegen turns it into
src/holidays_table.c. Tests make sure the original four IDs do not move,
date rules resolve correctly, and duplicate IDs do not sneak in.
That is the right shape for this problem. Calendar rules belong in data. Runtime lookup belongs in C. The generated file should be boring.
The sprite-sheet correction
The first AI pass got the problem wrong. It drew scenes. Palm trees, sand, sky, Johnny. Pretty little concepts, totally wrong for the runtime.
The actual runtime composites an overlay sprite on top of the existing island. So the art had to be transparent-background props: eggs, lightsaber, tiny chalkboard, football, medal, peace medallion, hibiscus, ballot box. 32x32 cells in a shared 16-color CLUT. Index 0 transparent. No Johnny. No island. No sand.
Once that constraint was enforced, the sheet snapped into focus.
Algorithms over tables
The important decision was not to ship a list of dates.
Easter uses the Meeus / Jones / Butcher algorithm. Nth weekday holidays use a small date helper. Election Day follows the “Tuesday after the first Monday in November” rule. Fixed holidays compare month and day. The runtime can answer future dates without waiting for me to update a table in 2030.
This is overkill in the best way. The visual output is a 32-pixel watermelon. The date engine under it is correct.
What codegen bought
It bought fearlessness. Adding a holiday became:
- Add a row to YAML.
- Add or adjust the emblem.
- Regenerate.
- Run tests.
- Review in the pause menu date picker.
No hand-edited C table. No stale title string. No date rule duplicated in a second file. The generated page set under /docs/holidays/ is part of the same bargain: the data produces the runtime table and the documentation.
Cross-links
- Holidays
- Date-algorithm core
- Holiday emblem gallery
- AI sub-agents on this project — the sprite primitives that compose into the emblem sheet were drafted by an LLM sub-agent; that page records the human-edit pass that reviewed them.
- The LLM pass — the methodology essay whose loop this codegen story is one case study of.
- 4/20 Day