diff --git a/docs/design-guidelines.md b/docs/design-guidelines.md index 780b2a1f..0995b468 100644 --- a/docs/design-guidelines.md +++ b/docs/design-guidelines.md @@ -78,8 +78,8 @@ When there's **exactly one slice** (one language at 100%), the renderer emits tw | Metric | Value | | --- | --- | | Grid | 7 rows × 53 columns (Sunday → Saturday, oldest week → newest) | -| Cell size | 4 wide × 12 tall, 1 px gap. Width is constrained (`leftPad 30 + 53 × 5 = 295 px`, 45 px right gutter); height has headroom so cells are rectangular — makes each weekday row a distinct horizontal band instead of a postage-stamp blur | -| Grid y-range | `topPad(62) .. 62 + 7 × 13 = 153 px`; 32 px gap to the legend at y ≈ 185 | +| Cell size | 4 × 4 px square, 1 px gap. 4 is the largest square that fits with breathing room on both sides (`leftPad 30 + 53 × 5 = 295 px`, 45 px right gutter). 5 × 5 with a gap overflows; 5 × 5 touching cells loses visible separation; rectangular cells look stretched. Card has vertical headroom to spare — we accept that in exchange for a clean square grid | +| Grid y-range | `topPad(70) .. 70 + 7 × 5 = 105 px` | | Cell colour | 5-bucket ramp `mixHex(Background, Accent, k/4)` for `k ∈ 0..4` — no dedicated ramp field on the theme schema | | Weekday labels | Mon / Wed / Fri only, right-anchored in the `leftPad` gutter | | Month labels | Printed above the first week where a 1st-of-month day falls; skipped when `x > width − 20` so `Dec` / `Apr` can't spill past the frame | diff --git a/internal/card/contributions_heatmap.go b/internal/card/contributions_heatmap.go index e15c617e..01e37ba6 100644 --- a/internal/card/contributions_heatmap.go +++ b/internal/card/contributions_heatmap.go @@ -22,26 +22,20 @@ func (contributionsHeatmapCard) SVG(p *github.Profile, t theme.Theme) ([]byte, e // theme.Accent in four intensity buckets so every palette inherits a usable // heatmap without a separate color ramp in the theme schema. // -// Cells are intentionally rectangular: width is constrained by 53 weeks -// fitting in 340 − leftPad − rightPad, but height has lots of spare card -// real estate, so we make cells ~3× taller than wide. That turns the grid -// into distinct horizontal bands instead of a cramped postage-stamp. -// -// Geometry: -// -// width per column = cellW + cellGap = 4 + 1 = 5 px → 53 * 5 = 265 px -// leftPad 30 + 265 = 295 px grid right edge, 45 px right gutter -// height per row = cellH + cellGap = 12 + 1 = 13 px → 7 * 13 = 91 px -// grid y-range: 62 .. 153 (leaves 32 px gap to the legend at y ≈ 185) +// Cells are square. 53 weeks at (cellSize + gap) = 5 px per column fills +// 265 px, which leaves comfortable left (30) and right (45) gutters inside +// the 340 px card. 6 × 6 cells would overflow; 5 × 5 cells with a gap push +// back to the right edge. 4 × 4 is the largest square that keeps breathing +// room on both sides. The resulting grid is short (35 px tall) — the card +// has lots of vertical headroom — but short beats awkwardly stretched. func renderHeatmap(title string, days []github.DailyContribution, t theme.Theme) []byte { const ( - width = 340 - height = 200 - cellW = 4 - cellH = 12 - cellGap = 1 - leftPad = 30 - topPad = 62 + width = 340 + height = 200 + cellSize = 4 // square + cellGap = 1 + leftPad = 30 + topPad = 70 ) var b strings.Builder @@ -74,7 +68,7 @@ func renderHeatmap(title string, days []github.DailyContribution, t theme.Theme) if label == "" { continue } - y := topPad + i*(cellH+cellGap) + cellH - 3 + y := topPad + i*(cellSize+cellGap) + cellSize - 1 fmt.Fprintf(&b, ` %s`, leftPad-4, y, t.Muted, label) @@ -95,7 +89,7 @@ func renderHeatmap(title string, days []github.DailyContribution, t theme.Theme) continue } lastMonth = first.Month() - x := leftPad + w*(cellW+cellGap) + x := leftPad + w*(cellSize+cellGap) if x > monthLabelMaxX { continue } @@ -112,11 +106,11 @@ func renderHeatmap(title string, days []github.DailyContribution, t theme.Theme) continue // padding slot before the first real day } fill := ramp[bucketFor(cell.Count, buckets)] - x := leftPad + w*(cellW+cellGap) - y := topPad + d*(cellH+cellGap) + x := leftPad + w*(cellSize+cellGap) + y := topPad + d*(cellSize+cellGap) fmt.Fprintf(&b, ` %s — %d`, - x, y, cellW, cellH, fill, + x, y, cellSize, cellSize, fill, cell.Date.Format("2006-01-02"), cell.Count) } }