Build 12/30: Word Counting Calendar Reboot

Posted Tuesday, October 28, 2025 by Sri. Tagged JOURNAL

The old NaNoWriMo org is dead, but there's still demand for Word Counting Calendars! I made a placeholder pdf, and will write software to generate them for the rest of this week.

About the Title Picture: This is what the hacked-together PDF software can do so far: draw a compact calendar, some bubbles, and make a 365-page ETP Journal. I'll want to expand it to make the word counting calendar by Friday.screenshot of code generating calendars and pdfsscreenshot of code generating calendars and pdfs (full size image)

Today's Sharepiece is an interim version of my NaNoWriMo Word Counting Calendar. It's an interim version because would love to have software generate these automatically with all the color variations. It's quite tedious to do them by hand even when I'm able to reuse a calendar.

For now, though, you can grab this retitled calendar from 2014, which happens to have the same days as 2025! Unfortunately, I didn't have the color templates in 2014 so we've just got the default green one.

Download Interim Word Counting Calendar for November

November 2025 calendar with weekly word counts and fill-in bubbles to track words written each dayNovember 2025 calendar with weekly word counts and fill-in bubbles to track words written each day (full size image)

Download Interim Calendar for Nov 2025

Storytime with Sri: The Technical Details!

The official NaNoWriMo org shut down on April 2025There are at least two spiritual successors that I found: Nano2 and Writing Month. Still, a few people have reached out asking if I would be doing another one this year, and since they asked nicely I figured that I should keep updating them! However, making these calendars (especially with the color variants) has been a time-consuming effort and I must admit that I don't look forward to hours of eye-destroying work. So, this is a good reason to spend the rest of the week writing software that will generate the calendars for me!

On a side note, I have been spending too much time on these daily challenges, so domestic chores and other self car activities had been pushed aside. With this in mind, today I restricted myself to three hours including the blog post. Otherwise, I end up blowing 7-8 hours on the production + writing tasks.

Anyway, I reviewed the codebase I had for the ETP 365-Day Journal using some Claude Code prompting to keep it from spewing garbage back at me. Here's my prompt:

I am reviewing code I wrote a year ago and want to generate a concise technical summary of each file. You are my assistant and do not ask questions. You do not offer suggestions. Our review process consists of developing a high level system overview and identifying the intent of code modules and particularly its API structure. I will be in "thinking aloud mode" as I chat, to which you should reply "input accepted. ready". Do not guess or assume what I am doing. Cite all your reasoning.

I followed-up with musing input like this:

Thinking aloud: I know that @pdfgen is the main entrypoint, which just runs the file @src/server/@pdfgen-main.mjs . It imports PDFMAKER and ESBUILDER as well as FONTUTILS. It is these modules I want to examine.

I then asked Claude to summarize the code I'd written last year, having the AI produce individual module references like this one for the PDFMAKER module:

I had to give Claude an example of what a "concise reference" looked like by cleaning up its initial output, as it tended produce documentation that was filled with extraneous info that you might see in a crappy online API reference

util-pdf.mjs Technical Reference

Purpose: Generate almanac-style planner PDFs with embedded fonts, form fields, and date-specific pages.

API Methods

CapturePDF(url, path)

Captures web page as PDF using Puppeteer headless browser.

MakePDF(layoutName)

Generates complete almanac PDF for specified layout (US-C1, A4-C1). Embeds fonts, loads background template, iterates almanac dates, renders date fields as SVG paths, creates form fields.

Font Management

m_EmbedFonts(pdfDoc, fontsOb)

Embeds all fonts from FONTS definition into PDF document.

m_GetFontPath(fontName)

Returns absolute path for font file.

m_GetEmbeddedFont(fontName)

Returns pdf-lib font instance for text rendering.

m_GetOpenFont(fontName)

Returns OpenType font instance for SVG path generation.

Text Rendering

m_DrawString(page, fieldName, text, opt)

Draws text using layout field coordinates, handles alignment modes, caches extents.

m_DrawTextAsSvg(page, fieldName, text, opt)

Renders text as SVG path for precise typography using OpenType font data.

m_RenderTextToSvgPath(fontName, text, fontSize)

Converts text to SVG path string with bounding box using OpenType.js.

Layout Operations

m_GetTextExtents(fieldName)

Returns text field positioning data from layout table for display fields.

m_GetTextFieldExtents(fieldName)

Returns positioning data for form input fields.

m_DrawLayoutGrid(page, opt)

Renders layout guide markers for debugging.

m_DrawBbox(page, opt)

Draws bounding box for visual debugging.

Key Concepts

  • FONTS object: Central registry mapping font names to paths, embedded instances, buffers, and OpenType instances
  • Layout system: Field definitions accessed via ALMANAC.DBG_Tables providing coordinates and alignment
  • Dual rendering: Text rendered both as pdf-lib text (forms) and SVG paths (precise date display)
  • Field types: 'input' (editable forms), 'center'/'right'/'left' (static text alignment)

This will be helpful for tomorrow, when I start to get into the code again. It's messy and I will be tempted to refactor it a bit, but I'll try to stay ON FOCUS so I can generate my pretty colored calendars.

All Building Challenge Posts

This challenge starts October 11th and ends when 30 artifacts have been posted. Weekends are exempt from production.

URSYS Web App Template

Embedded TypeScript Apps in Eleventy

A Review of Old Work and Stories

Eleventy Templates for Atom Feeds

Productivity Energy Crash

Workshopping the 'Activity Bingo' Form (part 1)

Last Run of ETP Notebook Production

Activity Bingo Form Progress (part 2)

ETP Mini Notebook Printing Press Tour

Identity and Logo Thinking Pass

Unprofessional Business Cards

Word Counting Calendar Reboot

BUILD CHALLENGE COMMENTARY

I got started at around 1:30PM, and am finishing up around 3:45PM. This will give me some time to do the neglected chores that have been stressing me out.

I'm not sure how long the software will take. I think I already started working on it last year...ah, there are some functions already in place like this one!

function WC_CalendarProps(dateString: CC_DateString = '2023-11-01'): TWC_MonthData {
const fn = 'WC_CalendarProps';
const date = Temporal.PlainDate.from(dateString); // Parse the date string
//
const firstDay = date.with({ day: 1 });
const firstWeekDay = firstDay.dayOfWeek; // monday = 1, sunday = 7
const firstWeek = firstDay.weekOfYear;
const firstWeekDayName = firstDay.toLocaleString('en-US', { weekday: 'short' });
const firstWeekDayName2 = firstWeekDayName.slice(0, 2).toUpperCase();
const lastDay = date.with({ day: date.daysInMonth });
const lastWeekDay = lastDay.dayOfWeek;
const lastWeekDayName = lastDay.toLocaleString('en-US', { weekday: 'short' });
const lastWeekDayName2 = lastWeekDayName.slice(0, 2).toUpperCase();
const lastWeek = lastDay.weekOfYear;

// Calculate the number of ISO weeks spanned by the month
const totalWeeks = lastWeek - firstWeek + 1;

...

BONUS ACHIEVEMENTS

It was a nice bonus to find that this year's NaNoWriMo calendar was the same as 2014, so that gives me some coverage. I put the updated site link on the new calendar too.

If I have time tonight, I'll update the old site's word counting calendar page with the new information so people can find it.


We chat about personal projects and challenges on the DS|CAFE Community Discord Server every day. Come visit! Maybe you'll make some friends!

You can reach me at Mastodon or Bluesky. Or subscribe to the blog feed to stay up-to-date.