Back to skills

github-contribution-wall

Create a GitHub contribution wall image from a user's contribution history. Use when the user wants a GitHub contribution graph, contribution wall, heatmap, 2D poster, or 3D contribution visualization, including custom duration, light/dark theme, and color palette variants.

Shared by catsjuice
github-contribution-wall

GitHub Contribution Wall

Create a polished GitHub contribution wall as an image. Support both a flat 2D heatmap and a 3D block version.

Resources

  • demo.png: visual reference image for composition and styling. If this file exists next to SKILL.md, inspect it before rendering and treat it as the primary style reference unless the user explicitly asks for something different.

Workflow

0) Inspect the visual reference first

If ./demo.png exists in the skill directory, inspect it before asking questions or rendering.

Use it to guide:

  • overall composition
  • camera angle
  • chart scale
  • legend placement
  • background treatment
  • spacing and margins
  • typography weight and hierarchy

Follow the reference image closely for look and layout, while still respecting:

  • the user's explicit preferences
  • the requested 2d or 3d mode
  • the required date range
  • the requirement that 3d output remains isometric

If the reference image conflicts with the user's explicit instructions, follow the user.

1) Collect only the missing inputs

First inspect the user's prompt. If it already contains any of the answers below, do not ask that question again.

Required inputs:

  • GitHub username
  • Duration / date range
  • Output style: 2d or 3d
  • Theme mode: light or dark
  • Color palette

If any inputs are missing, ask only for the unresolved ones. Keep the message short and practical. It is acceptable to ask all missing items in one message.

Use these defaults and choices when the user does not specify them:

  • Duration choices: last 3 months, last 6 months, last 12 months, year to date, or custom
  • Style choices: 2d or 3d
  • Theme choices: light or dark
  • Palette choices:
    • classic green
    • ocean blue
    • sunset orange
    • rose pink
    • mono gray
    • multiple palettes

User-supplied preferences always override these defaults.

Default visual preferences:

  • For 3d, the overall style must be isometric
  • For 3d, include the literal keyword isometric in any render brief or helper prompt you compose
  • For 3d, use a 45-degree horizontal viewing angle with a moderate elevation
  • For 3d, do not show ticks, axes, grid lines, axis labels, or axis frames
  • For 3d, place the legend at the bottom of the image
  • For 3d, render the legend as separate small 3D bars instead of flat swatches
  • For 3d, make every legend bar use the same square cross-section as the chart bars
  • For 3d, keep all bars fully opaque and non-transparent
  • For 3d, scale the chart up so the main wall dominates the canvas
  • Use a background that matches the selected palette and light or dark mode
  • Do not print an explicit Legend heading

When demo.png is available, prefer its visual decisions over these defaults unless that would violate the user's explicit request.

If the user chooses custom duration, ask for the exact start and end dates. If the user chooses multiple palettes, render multiple final images, one per palette.

2) Resolve the date range

Convert the chosen duration into an explicit date range before fetching data.

Rules:

  • Always state the final date range explicitly in the output.
  • Prefer full local dates in YYYY-MM-DD.
  • For last 12 months, use a rolling window ending today.
  • For last 12 months, fetch the full range from exactly 12 months ago through today, not an abbreviated recent subset.
  • For year to date, use January 1 of the current year through today.
  • When calling APIs, convert the range to explicit ISO datetimes so the full interval is preserved.

3) Try the direct render API first

Prefer the hosted ssr-contributions-img API as the first implementation path.

Repository:

  • https://github.com/CatsJuice/ssr-contributions-img

If you need deeper API customization such as theme selection, fully custom colors, gap tuning, or other render parameters, read the upstream documentation in this repository instead of guessing unsupported parameters.

Hosted endpoint:

https://ssr-contributions-svg.vercel.app/_/<username>?<queryString>

On this path, do not fetch GitHub contribution data yourself first. The API only needs the GitHub username and query parameters.

Map user choices to API parameters:

  • 2d -> chart=calendar
  • 3d -> chart=3dbar
  • light / dark mode -> dark=false / dark=true
  • Built-in palette -> theme=<themeName>
  • Custom palette -> colors=<hex1>,<hex2>,... which overrides theme

Recommended defaults for the API path:

  • format=png when you want to composite the chart onto a custom background and add your own labels
  • jpeg only if you specifically want the API to return an opaque white-background raster
  • quality=2 for png or jpeg
  • For 3d, enable outlines with strokeWidth and optionally strokeColor
  • For 3d, prefer gradient=false unless the reference image clearly uses gradient shading
  • For more advanced API controls such as theme variants, fully custom color sets, and gap tuning, consult https://github.com/CatsJuice/ssr-contributions-img

Recommended API query construction:

  • 2d example:
https://ssr-contributions-svg.vercel.app/_/CatsJuice?chart=calendar&format=png&theme=green&dark=false&weeks=26
  • 3d example:
https://ssr-contributions-svg.vercel.app/_/CatsJuice?chart=3dbar&format=png&theme=dark&dark=true&weeks=26&strokeWidth=1.2&strokeColor=111827

Duration mapping for the API path:

  • last 3 months -> about 13 weeks
  • last 6 months -> about 26 weeks
  • last 12 months -> a full year usually needs about 52 to 54 weeks

Important limitation:

  • According to the upstream README, the weeks parameter supports 1 to 50
  • If the user requests an exact last 12 months output, the API path may not be able to represent the full span exactly
  • In that case, use the API path only if the user accepts an approximation; otherwise fall back to the local rendering path below

If the API returns a suitable image:

  • Use it directly as the chart body, or
  • Composite it onto a larger final canvas with your own background, title, date range, and legend treatment

If the API is unavailable, rate-limited, fails, or cannot satisfy the requested duration or layout, continue with the local fallback path below.

4) Fetch contribution data for the local fallback path

Only do this when the API-first path is unavailable or unsuitable.

Prefer GitHub CLI first. Use a direct GitHub page fallback only if gh is unavailable or unusable.

Preferred path: gh api graphql

Use GitHub GraphQL to fetch the contribution calendar:

gh api graphql -f query='
query($login: String!, $from: DateTime!, $to: DateTime!) {
  user(login: $login) {
    contributionsCollection(from: $from, to: $to) {
      contributionCalendar {
        totalContributions
        weeks {
          contributionDays {
            contributionCount
            contributionLevel
            date
            weekday
            color
          }
        }
      }
    }
  }
}' -F login=USERNAME -F from=START_ISO -F to=END_ISO

Use full-day bounds for the request:

  • START_ISO: start date at T00:00:00Z
  • END_ISO: end date at T23:59:59Z

Target structure:

  • 7 rows for weekdays
  • N columns for weeks
  • Each day needs at least:
    • date
    • contributionCount
    • contributionLevel

Fallback path: fetch from GitHub pages

Try one of these in order:

  1. https://github.com/users/<username>/contributions?from=<start>&to=<end>
  2. https://github.com/<username>

Parse the contribution graph from the returned SVG or page markup. Extract day cells and their counts or intensity levels. If the HTML is used, inspect the contribution rect elements and related labels/tooltips. Normalize the result into the same day-based structure used by the gh path.

If both methods fail, stop and explain exactly what failed.

5) Normalize the data for rendering

Prepare a weekly grid:

  • Columns are weeks from left to right
  • Rows are weekdays from top to bottom
  • Missing leading or trailing days are allowed as empty cells
  • Preserve every returned week column. Do not crop, compress, or downsample weeks.

Duration sanity checks:

  • last 12 months should usually render about 52 to 54 weekly columns
  • If the output looks closer to 8 to 10 columns, treat that as a failure and fix the fetch or layout before finishing

For each day, keep:

  • date
  • count
  • level
  • week_index
  • weekday_index

For 3D output, derive a render height from count.

Recommended height mapping:

  • Use a capped or square-root scale so a few high-count days do not dominate the chart.
  • Example: height = max(1, round(sqrt(count))) for non-zero cells.
  • Zero-count cells should stay at height 0.

6) Render with implementation paths in priority order

Try these implementation paths in order.

Before rendering, write a short internal render brief that includes:

  • username
  • explicit date range
  • 2d or 3d
  • light or dark
  • palette
  • the literal keyword isometric for 3d
  • the key visual traits taken from demo.png when available

Option A: Direct third-party API render

Preferred as the first implementation path.

Use the hosted ssr-contributions-img service:

https://contribution.oooo.so/_/<username>?<queryString>

Rules:

  • Do not fetch GitHub contribution data in advance on this path
  • Build the output from username plus API query parameters
  • Use chart=calendar for 2d
  • Use chart=3dbar for 3d
  • Use theme and dark when the requested look matches built-in API themes
  • Use colors when you need a custom palette; this overrides theme
  • Prefer format=png so you can composite the returned chart on your own themed background
  • Use quality when outputting png or jpeg
  • For 3d, use strokeWidth and optionally strokeColor so cube outlines remain visible
  • If the service supports legend rendering for the requested chart, prefer the service-rendered legend first

Composition rules for the API path:

  • If the API output already matches the requested final look, you may deliver it directly
  • Prefer the third-party service's built-in legend when it matches the requested layout and style
  • If you still need title text, explicit date range, a custom background, or additional layout adjustments, composite the returned image onto a larger final canvas locally
  • Only replace or augment the API-rendered legend locally when the built-in legend cannot satisfy the requested position, style, or overall composition
  • Preserve the API-rendered chart as the main body of the final composition
  • When embedding the API-generated image into a larger composition, ensure it is integrated cleanly into the final design
  • Do not leave any extra background patch, border, outline, frame, or boxed panel around the embedded chart
  • Avoid visible seams, cutout edges, or collage-like stitching; the final image should feel like one unified piece

Duration rules for the API path:

  • Convert duration presets into weeks when possible
  • Remember that the upstream API documents weeks as 1 to 50
  • If the user requests an exact last 12 months result, do not silently compress it into a shorter-looking chart
  • Fall back to a local renderer when the API cannot represent the requested span accurately enough

Option B: Pillow to PNG

Preferred for the local fallback path, especially for 3d.

2D:

  • Use square cells with small gaps.
  • Draw one rectangle per day with ImageDraw.rectangle.
  • Keep the grid centered and large on the canvas.

3D:

  • Draw simple isometric cubes or columns with polygons.
  • Keep the overall visual style isometric.
  • Use a 45-degree horizontal projection.
  • Compute isometric screen coordinates from each day's (col, row) grid position:
x = origin_x + (col - row) * bw // 2
y = origin_y + (col + row) * bh // 2
  • Treat bw and bh as the projected block width and height used by the isometric grid.
  • Build each day as 3 polygons: top face, left face, and right face.
  • Draw faces with ImageDraw.polygon().
  • Sort cubes back-to-front before drawing so nearer cubes paint over farther cubes.
  • Outline every visible face.
  • Trace polygon edges with ImageDraw.line().
  • Use a dark stroke color. A semi-transparent dark stroke is acceptable for edges, but cube faces must remain opaque.
  • Keep all bars opaque. Do not use transparency.
  • Keep each bar footprint square in the x/y plane.
  • Keep perspective modest and readable instead of dramatic.
  • Do not draw axes, ticks, grid lines, or axis labels.
  • Put a compact 3D-style legend at the bottom without a Legend heading.
  • Render the legend as separate 3D bars with the same square cross-section as the main chart bars.

Option C: matplotlib to PNG

Use if Pillow is missing or the polygon-based approach fails.

2D:

  • Use square cells with small gaps.
  • Draw one rectangle per day.
  • Keep the grid centered and large on the canvas.

3D:

  • Use mpl_toolkits.mplot3d and bar3d.
  • Use bar height based on normalized count.
  • Keep the overall visual style isometric.
  • Use a 45-degree horizontal viewing angle.
  • Prefer an orthographic or low-perspective look if the toolkit allows it.
  • Draw visible edges on every block.
  • Keep edge lines darker than the face color for separation.
  • Keep all bars opaque. Do not use transparency.
  • Keep each bar footprint square in the x/y plane.
  • Hide axes, ticks, grid lines, and axis labels.
  • Include a compact bottom legend because height is not self-evident.
  • Render the legend as separate 3D bars, not a continuous strip.
  • Use the same square cross-section for legend bars as for the main chart bars.
  • Do not add a Legend title or heading.

Option D: Python-generated SVG, then convert to image

Use if raster plotting libraries are unavailable.

Process:

  • Generate SVG from Python.
  • Convert to PNG with cairosvg if available.
  • If conversion tools are unavailable, try a local system conversion path.

Keep this path simple. Do not build a complex rendering stack when a basic SVG is sufficient.

7) Apply themes and palettes

Respect both theme mode and palette choice.

Theme rules:

  • light: light background, dark labels
  • dark: dark background, light labels
  • The background should not be a flat unrelated color.
  • Use a subtle background image, gradient, or low-contrast textured field derived from the same palette family as the chart.
  • Keep the background quieter than the chart so the wall remains dominant.

Suggested palettes:

  • classic green: GitHub-like green ramp
  • ocean blue: slate to cyan-blue ramp
  • sunset orange: warm amber-orange ramp
  • rose pink: dusty pink to red ramp
  • mono gray: neutral grayscale ramp

For each palette, define 4 or 5 non-zero intensity steps plus one zero-value background cell color.

When using the API path:

  • Prefer theme when a built-in theme is a close match
  • Prefer colors when you need exact palette control
  • Remember that colors overrides theme
  • Prefer png plus local compositing when you need a custom palette-linked background image

If the user asks for multiple palettes:

  • Render one final image per palette
  • Keep layout, size, and labeling consistent across outputs

8) Compose the final image

The chart must be the main subject.

Layout requirements:

  • Put the GitHub username at the top
  • Show the exact date range under or near the title
  • Keep the contribution wall centered
  • Make the wall occupy most of the image area
  • Avoid large empty margins

For 3D output:

  • Use a larger overall chart scale than the 2D version
  • Avoid large empty areas around the wall
  • Include a compact bottom legend
  • Render the legend samples as 3D bars
  • Separate legend bars into distinct individual columns
  • Make legend bar footprints square, matching the main chart bars
  • Explain either the count buckets or the height mapping
  • Do not show an explicit Legend label
  • Keep the legend outside the main chart body

For long ranges such as last 12 months:

  • Allocate enough horizontal space for the full weekly span
  • Do not crop the leftmost or rightmost weeks
  • If necessary, widen the canvas or reduce gaps before reducing the visible date span

Optional metadata:

  • Total contributions in the selected range
  • Palette name
  • 2D or 3D label

9) Quality rules

Before finishing, verify:

  • Username is correct
  • Date range is correct and printed on the image
  • Grid orientation is correct
  • The chart is visually centered
  • The chart fills most of the canvas
  • 3D blocks have visible outlines
  • 3D blocks are opaque and not transparent
  • 3D style reads as isometric
  • Text is readable against the background
  • Exported image is not cropped or blurry

For last 12 months, also verify:

  • The chart shows roughly 52 to 54 weekly columns
  • The image does not look like only the most recent 2 months
  • The full requested date span is visible in both the data and the composition

For the API path, also verify:

  • The generated URL parameters match the requested style and duration
  • The API did not silently return a shorter-looking chart than requested
  • If the API image is only the chart body, the final composition still includes the required labels and background treatment

If the result looks too small, increase cell size and reduce padding before trying a new design.

Practical defaults

Use these defaults unless the user requests otherwise:

  • Output format: png
  • Canvas:
    • 2d: landscape, around 1600x900
    • 3d: landscape, around 2200x1300
    • 3d for last 12 months: prefer an extra-wide layout, around 2400x1300 or wider
  • Typography: simple sans-serif
  • Filename format:
    • github-contribution-wall-<username>-<start>-to-<end>-2d-<palette>.png
    • github-contribution-wall-<username>-<start>-to-<end>-3d-<palette>.png

Response behavior

When starting:

  • Briefly confirm the resolved inputs
  • Mention whether you are using the direct API path or the local fallback path
  • If the style is 3d, explicitly describe it as isometric

When finishing:

  • State what was generated
  • State which implementation path succeeded
  • Include the output file path or paths
  • If multiple palettes were requested, list every generated image

If blocked:

  • Say which step failed
  • Include the exact missing dependency or fetch failure
  • Do not claim the wall was generated unless the image file exists

Bridging AI and Skills

Get Started