A pixel-art Christmas tree that grows from your GitHub contributions this year. It starts as a bare green tree in January; as you commit, snow piles up and ornaments unlock one by one, and a crown star π appears once you hit a big year.
4 themes β
defaultπ /spaceπͺ /winterποΈ /skyβοΈ. The backgrounds are animated.
πΊπΈ English Β· π°π· νκ΅μ΄
A self-updating widget for your GitHub profile README. Once a day a GitHub Action reads your contribution count for the current year (Jan 1 β today) and regenerates an SVG image of a Christmas tree decorated to match, then commits it back to your repo.
- Animated background β twinkling stars, drifting clouds, meteor showers, and falling snow. (Not a GIF β infinite-loop animated SVG.)
- Snow accumulates with your commits β a bare green tree early in the year, gradually covered in snow as your contributions grow. (Accumulated snow never disappears.)
- Per-user randomized layout (seeded by username) β even with the same commit count, every tree looks different.
- The same person always gets the same layout, so the tree doesn't jitter day to day.
- 100% original pixel art drawn in code β no game assets, free to use.
A README can't run code, so the trick is to "redraw an image on a schedule."
GitHub Action (daily cron)
ββ fetch this year's contributions (GraphQL: contributionsCollection)
ββ render SVG tree (background + ornaments = based on contributions)
ββ commit to repo (README shows that SVG via <img>)
Create a repo with the same name as your GitHub username (username/username).
Its README.md is shown on your profile page. (If you already have one, just use it.)
Create .github/workflows/build-tree.yml in your profile repo and paste the following.
(Defining theme as a choice input lets you pick a theme from a dropdown under Actions β Run workflow.)
name: Build Christmas Tree
on:
schedule:
- cron: "0 18 * * *" # once a day (18:00 UTC)
workflow_dispatch: # manual run from the Actions tab (theme dropdown)
inputs:
theme:
description: "Background theme"
type: choice
default: default
options: [default, space, winter, sky]
push:
branches: [main]
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Generate tree
uses: chromeheartz/merry-gitmas@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
theme: ${{ inputs.theme || 'default' }} # default | space | winter | sky
width: 350 # image width in px (default 350)
output: profile-tree.svg
- name: Commit SVG
uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "chore: update christmas tree π"
file_pattern: profile-tree.svgWrapping it in a link so clicking the image leads back here is recommended:
[](https://github.com/chromeheartz/merry-gitmas)To tweak the size, change the
widthinput, or use HTML like<a href="..."><img src="./profile-tree.svg" width="350"></a>.
Go to the Actions tab β Build Christmas Tree β Run workflow to generate the first image.
After that it updates automatically every day.
π‘ No fork needed! Just reference it with a single
uses:line. Only fork if you want to customize the tree design yourself.
The tree starts bare and green on January 1st. As your contribution count grows, snow gradually builds up (fully unlocked at 300), and each milestone unlocks new colors and items.
| Contributions this year | Unlocked decoration |
|---|---|
1 |
π‘ lights |
8 |
π΅ blue baubles |
25 |
π‘ gold baubles |
45 |
β green stars |
70 |
π΄ red baubles |
100 |
β¨ gold stars |
140 |
π¬ candy canes |
185 |
π blue stars |
235β270 |
extra ornaments (full tree) |
300 |
βοΈ full snow + π crown star on top |
All thresholds can be tuned directly in
src/render/tree.tsvia theUNLOCKS/CROWN_ATconstants.
The theme input selects the background. The tree and ornaments stay the same β only the background changes, and it animates.
| Value | Background | Animation |
|---|---|---|
default |
night sky + moon | β¨ twinkling stars |
space |
pixel cosmos + planets | βοΈ meteor shower |
winter |
snowy mountains + conifers | βοΈ heavy falling snow |
sky |
blue sky + puffy clouds | βοΈ drifting clouds |
The crown star (300 commits) twinkles in every theme. All animations are infinite-loop SVG, not GIFs β lightweight and crisp.
Add new themes in THEMES inside src/render/themes.ts.
| Name | Required | Default | Description |
|---|---|---|---|
github_token |
β | β | Token to read contributions. ${{ secrets.GITHUB_TOKEN }} |
username |
β | repo owner | GitHub username to render the tree for |
theme |
β | default |
Background theme (default / space / winter / sky) |
width |
β | 350 |
Image width in px (height auto from aspect ratio) |
output |
β | profile-tree.svg |
Output SVG path |
npm install
# Quick preview without the API β preview.svg
npm run preview
TOTAL=300 THEME=space npm run preview # fake a state via env vars
# Run against real GitHub data
GITHUB_TOKEN=ghp_xxx USERNAME=yourname npx ts-node src/main.tsPreview env vars: TOTAL (this year's contributions), MAXDAY, STREAK, THEME, YEAR, USERNAME.
The Action runs the bundled dist/index.js, so the build output must be committed.
npm run package # bundle src β dist/index.js (ncc)
git add dist && git commit -m "build dist"
git tag v1 && git push --tagsOthers can then use it via uses: chromeheartz/merry-gitmas@v1.
| What | Where |
|---|---|
| Unlock thresholds / crown | src/render/tree.ts β UNLOCKS, CROWN_AT |
| Tree shape / proportions | src/render/tree.ts β TIERS |
| Ornament types / colors | src/render/tree.ts β SPRITE, palette.ts |
| Background themes | src/render/themes.ts |
MIT