BUILD 19/30: Calendar Day Drawing Progress

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!

Document List

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

Last Run of ETP Notebook Production

Activity Bingo Form Progress

ETP Mini Notebook Printing Press Tour

Identity and Logo Thinking Pass

Unprofessional Business Cards

Word Counting Calendar Reboot

Word Counting Calendar Interim Release

Calendar Layout Code Progress

Super Simple PDF Progress (1)

Articulating Friendship

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

A PDF-LIB Reference

Programatic Drawing of Word Counting Calendar Blocks (2)

Minimum Progress Despite Nausea; useful noobly attitudes (3)

Calendar Day Drawing Progress (4)

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.