Your GitHub profile README is the one page you fully control. Most of us fill it with badges and stat cards. I wanted something alive, so I built GitTulkun: a pixel-art Tulkun (the giant whale-like creatures from Avatar's Pandora) that is generated from your real GitHub activity, swims in a seamless looping GIF, and grows up as your year goes on.
PramudithaN
/
git-tulkun
Procedural pixel-art Tulkun whale generated from your GitHub contributions and language colors as a looping GIF for your profile README.
git-tulkun
A procedural pixel-art Tulkun leviathan for your GitHub profile README.md that resets to a baby calf every January 1st, grows on a logarithmic scale into an armored adult bull from your contributions, and takes its colors from your top programming languages.
Live git-tulkun generated from @PramudithaN's current-year GitHub activity (1,072 contributions - Stage 3: Adolescent Tulkun)
Quick Start (1-Step Setup)
1. Add this embed snippet to your profile README.md (replace YOUR_USERNAME with your GitHub username):
<p align="center">
<a href="https://github.com/PramudithaN/git-tulkun">
<img src="https://raw.githubusercontent.com/YOUR_USERNAME/YOUR_USERNAME/output/tulkun/tulkun.gif" width="640" alt="git-tulkun swimming" />
</a>
</p>
2. Create .github/workflows/tulkun.yml in the same repository (the action pushes tulkun.gif, tulkun.png, and share-card.png to an orphan output branch automatically so daily updates never bloat your main commit history):
name: Update Tulkun
on:
schedule: [{ cron: "0 0 * *…That is my own whale, generated live from my own contributions.
What it does
- Reads your current-year contributions and top repository languages from the GitHub GraphQL API
- Maps your contribution count to one of five life stages, from Baby Calf to Adult Male Bull
- Resets every January 1, so everyone starts the year as a calf
- Tints the whale with the official GitHub colors of your top three languages
- Renders a 48-frame, 15 FPS loop that updates daily through a GitHub Action
The five stages
| Stage | Contributions this year | What changes |
|---|---|---|
| 1. Baby Calf | [range] | Short, stubby body, blunt snout, cream belly |
| 2. Yearling Calf | [range] | Longer, slimmer body; kuru whips sprout |
| 3. Adolescent | [range] | Sensor crest rises; six flippers elongate |
| 4. Adult Female | [range] | Dark carapace armor, sloped crest, serrated jaw |
| 5. Adult Male Bull | [range] | Maximum length, hooked hammer-crest, battle scars |
How the renderer works
There are no spritesheets. Every frame is computed from a handful of parameters, so one code path draws all five stages and three camera angles.
1. Shape. The body is a spline, with signed distance fields (SDFs) for the head crest, flippers, whips, jaw stripes and flukes. A stage change just moves parameters, such as the spine growing from 64 px to 186 px.
2. Lighting. For each pixel the renderer builds a surface normal from the body's cylindrical profile and lights it with a fixed directional light:
n = (nx, ny, sqrt(1 - nx^2 - ny^2))
light = [-0.30, -0.62, 0.72]
3. Pixel-art look. Brightness is quantized to a 4-shade ramp with a 4x4 ordered Bayer dither matrix, which gives the classic crosshatch of old pixel art. A 1 px dark outline (#0f121a) keeps the whale readable on both light and dark GitHub themes.
4. Language colors. Each top language's hex color becomes a 4-shade ramp (shadow, mid dark, mid light, highlight). Your top language paints the belly, skin and carapace, the second tints the sensor crest, and the third lights its tip. A TypeScript-heavy profile gets a different whale than a Rust-heavy one.
5. Swimming. The loop is 48 frames at 15 FPS (3.2 seconds). A traveling S-wave bends the torso and drives the tail, while the flippers lag behind in phase:
dy(u, t) = A_bob * sin(w*t) * (1 - u)^1.3 + A_tail * sin(2.35*pi*u - w*t) * u^0.92
Here u runs along the body from head (0) to tail (1).
6. No jitter. The camera box is precomputed across the whole stroke, so the whale never clips or bounces the frame. Output is upscaled 2x with nearest-neighbor into a 640x280 GIF, plus a PNG and an HTML preview.
Why Rust and a GitHub Action
The whole thing is one Rust binary with five dependencies (chrono, gif, png, serde, serde_json). The composite GitHub Action downloads a prebuilt binary when one exists and compiles from source otherwise. Data collection shells out to gh api graphql, so the built-in workflow token is enough.
Add your own whale
Create .github/workflows/tulkun.yml in your profile repository:
name: Update Tulkun
on:
schedule:
- cron: "17 0 * * *"
workflow_dispatch:
permissions:
contents: write
jobs:
tulkun:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: PramudithaN/git-tulkun@[latest tag, e.g. v1]
with:
view: side
canon: "false"
- run: |
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add tulkun/tulkun.gif tulkun/tulkun.png
git diff --cached --quiet || git commit -m "chore: update Tulkun"
git push
[If you shipped a commit input or an output-branch option, show the shorter workflow here instead.]
Then embed it in your README:
<img src="tulkun/tulkun.gif" width="640" alt="My Tulkun" />
Want a preview without any setup? Run the demo mode locally:
cargo run --release -- demo --commits 145 --view dive --output-dir tulkun-demo
What I learned
[Add 2 or 3 honest lessons here, for example: keeping five stages visually consistent, getting a seamless loop, or the repo bloat from daily GIF commits and how you fixed it. Real stories earn more comments than feature lists.]
What I would love feedback on
- Should the stages scale differently, or use a rolling 365 days instead of a calendar year?
- What else should shape the whale: pull requests, reviews, streaks?
- Which camera angle do you like most?
Drop your whale in the comments, I would love to see them.
Repo: https://github.com/PramudithaN/git-tulkun (if you like it, a star helps others find it).
GitTulkun is an unofficial fan project. Tulkun and Avatar belong to their respective owners, and this project is not affiliated with or endorsed by them.



Top comments (0)