ModsCodeMERGEBLE LLC Search Claude Code Mods

ModsCode / Gallery / Designs / Month calendar

Month calendar

A month grid from Monday with one dot per event kind in its own slot, a counted legend, and today outlined in Claude orange.

Month calendarMonth calendar
Work and agents · 380×240 · sample data
hooks/designs/calendar-month.mjs
// calendar-month: October 2026 as a month grid in candle's look, weeks from Monday like the heatmap.
// The month is fixed, not read from a clock: the 1st is a Thursday (column 3), so 3 blank cells lead,
// the 31st is a Saturday and the grid closes at exactly 7 x 5. Cells are faint areas (ink 0.08) with a
// 2px gap instead of lines, so there is no frame; weekend day numbers sit at 0.42 so the work week leads.
// Each day carries up to three r=2 dots, one per kind in a fixed slot: deploy, review and meeting as
// ink 0.9 / 0.65 / 0.42. Friday the 9th is today, the only Claude orange on the sheet. The dots come from a
// seeded walk (seed 20261033): weekdays 30% / 50% / 40% per kind, weekends 6% / 6% / 0%, which gives
// 8 deploys, 14 reviews and 5 meetings, 27 in all. The legend counts and the total are counted from
// the same days, so they cannot drift from the dots; the caption names what the dots are rather than
// repeat the month the header already shows. Sample data only.
const W = 380
const H = 240
const STAGE = '#FAF9F5'
const INK = '#141413'
const MUTED = '#73726C'
const CLAUDE = '#D77757'
const FONT = "'Inter Tight','Segoe UI',system-ui,sans-serif"
const X0 = 12
const Y0 = 40
const CW = 49 // cell width; the pitch adds a 2px gap
const CH = 33
const PX = CW + 2
const PY = CH + 2
const FIRST = 3 // Thu 2026-10-01 in a Monday-first week
const DAYS = 31
const TODAY = 9
const KINDS = [
  { name: 'DEPLOY', opacity: 0.9, p: [0.3, 0.06] },
  { name: 'REVIEW', opacity: 0.65, p: [0.5, 0.06] },
  { name: 'MEETING', opacity: 0.42, p: [0.4, 0] },
]
const f = n => n.toFixed(1)
const WEEKDAY = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'][(FIRST + TODAY - 1) % 7]
const NTH = TODAY + (TODAY >= 11 && TODAY <= 13 ? 'th' : ['th', 'st', 'nd', 'rd'][TODAY % 10] ?? 'th')

// A seeded walk, so the picture is the same on every render
function rng(seed) {
  return () => (seed = (Math.imul(seed, 1103515245) + 12345) & 0x7fffffff) / 0x7fffffff
}

const text = (x, y, s, { size = 9, fill = MUTED, anchor = 'start', opacity } = {}) =>
  `<text x="${f(x)}" y="${f(y)}"${anchor === 'start' ? '' : ` text-anchor="${anchor}"`} font-size="${size}" font-family="${FONT}" fill="${fill}"${opacity ? ` fill-opacity="${opacity}"` : ''}>${s}</text>`

// For each day, the kinds it holds (indexes into KINDS, in legend order)
function sample() {
  const rnd = rng(20261033)
  const days = []
  for (let d = 1; d <= DAYS; d++) {
    const weekend = (FIRST + d - 1) % 7 >= 5
    days.push(KINDS.map((k, i) => (rnd() < k.p[weekend ? 1 : 0] ? i : -1)).filter(i => i >= 0))
  }
  return days
}

function draw() {
  const days = sample()
  const parts = [`<rect width="${W}" height="${H}" rx="4" fill="${STAGE}"/>`]
  parts.push(text(12, 18, 'OCTOBER 2026'))

  // The legend runs to the right edge; each entry is a dot, its name and its count for the month
  const entries = KINDS.map((k, i) => ({ ...k, label: `${k.name} ${days.filter(d => d.includes(i)).length}` }))
  const widths = entries.map(e => 8 + e.label.length * 5.5)
  let lx = W - 12 - widths.reduce((s, w) => s + w, 0) - 10 * (entries.length - 1)
  entries.forEach((e, i) => {
    parts.push(`<circle cx="${f(lx + 2)}" cy="15" r="2" fill="${INK}" fill-opacity="${e.opacity}"/>`)
    parts.push(text(lx + 8, 18, e.label))
    lx += widths[i] + 10
  })

  ;['M', 'T', 'W', 'T', 'F', 'S', 'S'].forEach((s, c) => parts.push(text(X0 + c * PX + 6, Y0 - 6, s)))

  days.forEach((kinds, i) => {
    const day = i + 1
    const slot = FIRST + i
    const x = X0 + (slot % 7) * PX
    const y = Y0 + Math.floor(slot / 7) * PY
    const weekend = slot % 7 >= 5
    parts.push(`<rect x="${x}" y="${y}" width="${CW}" height="${CH}" fill="${INK}" fill-opacity="0.08"/>`)
    if (day === TODAY) {
      parts.push(`<rect x="${f(x + 0.5)}" y="${f(y + 0.5)}" width="${CW - 1}" height="${CH - 1}" fill="none" stroke="${CLAUDE}" stroke-width="1"/>`)
    }
    parts.push(text(x + 6, y + 13, String(day), { size: 10, fill: day === TODAY ? CLAUDE : INK, opacity: weekend ? 0.42 : undefined }))
    // Each kind keeps its own slot, so a gap says which kind is missing as well as the shade does
    kinds.forEach(k => {
      parts.push(`<circle cx="${f(x + 8 + k * 7)}" cy="${f(y + CH - 8)}" r="2" fill="${INK}" fill-opacity="${KINDS[k].opacity}"/>`)
    })
  })

  const total = days.reduce((s, d) => s + d.length, 0)
  parts.push(text(W - 12, H - 8, `${total} EVENTS`, { anchor: 'end' }))
  parts.push(text(12, H - 8, 'SAMPLE EVENTS BY DAY'))
  return `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 ${W} ${H}" width="${W}" height="${H}">${parts.join('')}</svg>`
}

let source // drawn on first use and kept: the pane loads every design, so none pays at load time
export default {
  id: 'calendar-month',
  title: 'Month calendar',
  category: 'work',
  description: 'A month grid from Monday with one dot per event kind in its own slot, a counted legend, and today outlined in Claude orange.',
  element: ui => ui.Svg({ source: (source ??= draw()), alt: `Month calendar of October 2026 with deploy, review and meeting dots on the days that hold them and ${WEEKDAY} the ${NTH} outlined as today, sample data`, width: W, height: H }),
}

To use it in a mod: copy the file to your mod's hooks/designs/ and return its element(ui) from a pane's ui.render. How a pane is built.

Code: PolyForm Noncommercial License 1.0.0: noncommercial use only. Required Notice: Copyright 2026 Haruki Nakada (https://modscode.com).