Workshop Kit · widget reference

Shipped

rhythm-calendar

The last widget in the bootcamp. Month-view calendar with recurring task pins (hours / reviews / regenerate / SEO) and a real .ics export that drops four RRULE'd recurring events straight into Google Calendar, Apple Calendar, or Outlook. The .ics is generated entirely client-side from MuntinContext.rhythmCadence — Blob URL download, no fetch, no server.

Live demo

Change a cadence — the month grid below repopulates with pins on the days that cadence lands. Click Download calendar file to get the .ics. Open it in your calendar app; the recurring events go live immediately.

No config block — four tasks + the cadence dropdowns are baked in

Current MuntinContext.rhythmCadence Change a cadence above…

Contract

BehaviorNotes
Reads rhythmCadence Pre-fills the four cadence dropdowns. Defaults to hours=monthly, reviews=biweekly, regen=monthly, seo=quarterly when not set.
Reads restaurantProfile.name Appended to the SUMMARY of each .ics event so an operator with multiple calendars can tell which restaurant the event belongs to.
Writes rhythmCadence { hours, reviews, regen, seo } with each value one of: 'off', 'weekly', 'biweekly', 'monthly', 'quarterly'.
Legacy string handling The L16 lesson previously stored rhythmCadence as a free-text string (operator-typed). On first mount, the widget ignores anything that's not an object and writes the structured object on the next change — operators don't lose progress, but the schema upgrades.
.ics export Generated client-side using the VCALENDAR/VEVENT/RRULE specification. First event lands on the upcoming Monday at 9 AM local time; recurrences follow the FREQ rule. Filename: muntin-rhythm.ics.
No fetch Blob URL + document.createElement('a').click(). No third-party service, no server endpoint. The file lives in the operator's Downloads folder; the calendar app opens it directly.

Markup

<section class="course-widget" data-widget="rhythm-calendar"></section>

No config block. The four tasks + their default cadences are baked into the widget module.

What the .ics file contains

One BEGIN:VEVENT block per task whose cadence isn't "off":

BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Muntin Digital//Rhythm Calendar//EN CALSCALE:GREGORIAN BEGIN:VEVENT UID:reviews-20260525T090000@muntin.digital DTSTAMP:20260525T090000 DTSTART:20260601T090000 DTEND:20260601T093000 RRULE:FREQ=WEEKLY;INTERVAL=2 SUMMARY:Reviews triage (Muntin rhythm) — Jolene's Cafe DESCRIPTION:Open GBP. Respond to every new review. END:VEVENT ... END:VCALENDAR

30-minute slots starting 9 AM local on the first Monday after the download. Google Calendar, Apple Calendar, and Outlook all import this format directly via "open with" or drag-and-drop.

Accessibility

Why .ics and not a paid scheduling API

Calendar integrations could route through Google Calendar's API or Cal.com's webhooks, both of which would require auth flows + server-side credentials. The .ics format is the open standard those services themselves build on — every calendar app on every platform has imported .ics for decades. Generating it client-side and downloading a file preserves the suite's "no fetch, no account" posture while still delivering a real recurring-event setup. The operator's rhythm goes live on their phone the moment they tap the file.

Where it ships

Source

/tools/_shared/workshop/rhythm-calendar.js — ~290 LOC. Exports { tag, contextKeys, mount, serialize }. The TASKS array is the four-task contract; RRULE is the cadence-id → FREQ-rule mapping; buildICS() generates the VCALENDAR file; nthCadenceDays() computes which day-of-month each cadence lands on for the pin overlay.

← Back to the Workshop Kit