BUILD 19/30: Word Counting Calendar Drawing Blocks II

Posted Monday, November 10, 2025 by Sri. Tagged JOURNAL

Progress on drawing the Word Counting Calendar programmatically from parameter data. Getting closer!

About the Title Picture: Drawing Calendar Days with the parameterized cell renderer into a PDF document. The color is picked randomly. Next step is to draw a legimate calendar based on actual dates.A title image that says DAY 19, showing 6 rows of 8 calendar days numbered from 01 to 48, each a different color.A title image that says DAY 19, showing 6 rows of 8 calendar days numbered from 01 to 48, each a different color. (full size image)

I felt a lot better on Sunday, so I made up for lost time by working on the PDF generator for Word Counting Calendars! The cell drawing uses a constructed grid based on key subjects, which means that I can change the base grid size (used for drawing the blocks) and the labels (both font and size) and the cell will redraw correctly.

Figure 1. Closeup of a Calendar Day Cell, showing the rendering guidelines derived from from key elements like the DAY, the LABELS, and the PYRAMID.Closeup of Calendar Day Cell with red horizontal and vertical guidelines showing how each subelement of the cell is positioned relative to each otherCloseup of Calendar Day Cell with red horizontal and vertical guidelines showing how each subelement of the cell is positioned relative to each other (full size image)

The rendering order starts in the upper left, inset by a MARGIN. The DAY is drawn and the width is used to index to the next column, which is the alignment point for the LABELS and DIVIDER LINES before the PYRAMID is drawn. The size of the pyramid itself is determined by the BLOCK DIMENSION, which specifies the size of each individual BLOCK as well as the strokes, gaps, and proportional vertical spaces across the cell. Each cell also is drawn using a base color specified in a color table, using various opacity levels to achieve the unified color look.

Here's the parameterization that determines the cell's layout:

/// COLORS ///
const clr_default = [
cmyk(0.7423, 0.2818, 1, 0.1399),
cmyk(0.74, 0.0, 0.1, 0),
cmyk(0.57, 0.49, 0.59, 0.23),
cmyk(0.0, 0.55, 0.83, 0)
];
const clr_cell = R(clr_default);

/// PARAMETERS ///
const DIM = 8; // 8 pt is unit base
const DSIZE = 13; // fontsize of DAY
const LSIZE = 9; // fontsize of LABELS
const SSIZE = 5.5; // fontsize of SPECIAL

/// DERIVED PARAMETERS ///
const MRGN = DIM / 2;
const SWI = DIM / 8; // stroke width
const INS = SWI / 2; // stroke inset
const GAP = SWI * 3; // gap between boxes

The actual drawing code uses these values for spacing elements. There's a separate bit of code that precalculates the critical dimensions of elements:

// CALCULATE DIMENSIONS OF DYNAMIC ELEMENTS
const dayString = String(DAY).padStart(2, '0');
const DWIDTH = font.widthOfTextAtSize(dayString, DSIZE);
const DHEIGHT = font.heightAtSize(DSIZE, { descender: false });
const LABELS = ['2500+', '2250', '1750'];
let LWIDTH = 0; // text labels
for (let label of LABELS) {
const tw = font.widthOfTextAtSize(label, LSIZE);
if (tw > LWIDTH) LWIDTH = tw;
}
const LHEIGHT = font.heightAtSize(LSIZE, { descender: false });
let PWIDTH = (PSIZE - 1) * (DIM + GAP) + DIM; // pyramid
const PHEIGHT = PWIDTH;
const CELLW = MRGN + DWIDTH + GAP + LWIDTH + PWIDTH + MRGN;
const CELLH = MRGN + DHEIGHT + DIM + PHEIGHT + DIM + MRGN;
const SHEIGHT = font.heightAtSize(SSIZE, { descender: false });
const SWIDTH = font.widthOfTextAtSize(SPECIAL, SSIZE);

It's a bit fragile and janky as this is prototype code; I'll be cleaning it up later once I figure out the best way to write these kind of layout-based calculations more cleanly as components that have some kind of layout manager specific to my form design.

It was nice to spend several hours over the weekend getting this to work. I started with just this:

Figure 2. Closeup of previous Calendar Day Cell progress, showing the rendering guidelines derived from from key elements like the DAY, the LABELS, and the PYRAMID.Closeup of a Calendar Day Cell, showing just a pyramid block and labels and some guide lines for debugging purposesCloseup of a Calendar Day Cell, showing just a pyramid block and labels and some guide lines for debugging purposes (full size image)

Seems like good progress to me!

2025 Building Challenge Posts

Making an URSYS App Example

Adding Typescript support to Eleventy

Review of Old Design Work

Improving my Eleventy Atom Feeds

Managing a Productivity Crash

Activity Bingo Board: Layout with Affinity Designer

ETP 5885 Notebook Press Run Prep

Activity Bingo Board Revisions

ETP 5885 Notebook Press Tour

A Silly Pass at Logo Design

Unprofessional Business Cards

Word Counting Calendar PDF Quickie Reuse

Word Counting Calendar PDF Now Available!

Word Counting Calendar Preparing to Code

Word Counting Calendar Simple Beginnings

Articulating Friendship

First skip day due to day trip to Concord, etc.

Making a PDF-LIB Reference

Word Counting Calendar Drawing Blocks

Minimum Progress Despite Nausea

Word Counting Calendar Drawing Blocks II

Writing A Mythical Magical Adventure Cat Primer

Word Counting Calendar Drawing Days

Word Counting Calendar Drawing Spaces

A Restorative Visit to the North Shore

Word Counting Calendar: Alpha Release!

ETP 5885 Notebook Production Update!

Personal Cards Revisited

11/21 - Visiting an Old Friend in Beverly, MA

Experimental Collaboration

Short Productive Sprint Day

Thanksgiving Reset Break

ETP 5885 Notebook back on Amazon!

ETP 365 Day Journal Updated for 2026!

Making a Freelance Services Page

BUILD CHALLENGE COMMENTARY

I'm glad that the 3-4 day period of lethargy/nausea has passed, and I should get another couple of weeks of relatively good progress in. This is day 19, so there are just about two calendar weeks left before the 30-DAY BUILD CHALLENGE is completed.

So far, I think I've discovered a few things already:

  • I do like making things to share every day, even though they aren't always a finished project.
  • I've been working on different things (e.g. business cards, planning docs) as well as this software, but they're all related to delivering something that could serve my business needs. So, that's great! It seems sustainable so far.
  • The blogging process, including tooling, has stabilized! This means that writing online feels as effortless as it used to on early Wordpress 1.0!

There is an element of joy and whimsy that still seems missing, though. I'm hoping I stumble upon it in the next couple of weeks.

BONUS ACHIEVEMENTS

I had a look at ollama, which is a way to download and run open source Large Language Models (e.g. "AI Chat Bots") locally if you have enough memory in your computer. I happen to have an Apple Macbook Pro M1 which has unified memory, so I'm able to run the gpt-oss-20b model in about 15GB; it's roughly comparable to one of the "mini" models that are useful for doing document processing. By running these locally, I avoid incurring the cost of using a service that charges by the token.

Also, I am still totally obsessed by K-Pop Demon Hunters. It totally lights up my bitey little autistic heart.


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.