gh-space-shooter: a contribution graph rendered as a Galaga style GIF
Visualizes GitHub contribution graphs as Space Shooter!
At a glance
- What is it?
- gh-space-shooter is a Python CLI and GitHub Action that reads your GitHub contribution data and renders it as an animated space shooter image. It can run once from a terminal, on a schedule inside a repository, or on demand through a hosted web interface.
- Who is it for?
- gh-space-shooter fits a developer who wants a daily animated image in a profile README and is comfortable giving a workflow the contents: write permission and a token. Skip it for a profile that needs a static, accessible summary of activity, since an animated GIF of a game conveys less than a graph does, and skip it if you cannot expose a token with read:user scope.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 12 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
What the contribution square actually becomes in the animation
The premise is simple enough to explain in one line: your GitHub contribution graph becomes a space shooter game. The README describes what the frames contain. Your contribution graph appears as enemies, with more contributions producing stronger enemies, and a Galaga-style spaceship battles through your coding history. Enemy attack patterns follow the strategy you choose, particle effects are randomised for smoothness, and the contribution statistics are printed to the console when the run finishes. This is not a generic background generator that happens to read GitHub data. The number of commits in a given day is what determines the size and strength of the thing shooting at your ship, so a quiet month looks visibly different from a busy one. The audience is a developer who curates a GitHub profile README, and the output is meant to be committed as an image and shown with a Markdown image tag.
Three ways to run it: terminal, workflow and web interface
The project offers three distinct entry points, and they differ in who holds the token and who schedules the work. The web interface at gh-space-shooter.kiyo-n-zane.com generates the GIF on demand with nothing installed locally. The CLI runs from your shell. The GitHub Action, declared by the action.yml file at the repository root, regenerates the image on a schedule inside a repository and commits it. The CLI and the Action are the same Python package underneath, and the Action exists so that the daily run happens without your laptop being awake. The repository is also a uv workspace with an app member directory, which is where the web interface lives, and pyproject.toml registers the console entry point as gh-space-shooter = "gh_space_shooter.cli:app" using typer for argument parsing.
Installing from PyPI and producing the first animation
Installation from PyPI is a single command, and the project requires Python 3.12 or newer:
pip install gh-space-shooterThe dependency list in pyproject.toml is short and tells you what the tool does: httpx for the GitHub API calls, pillow for drawing and encoding the frames, typer for the command line, rich for the console output and python-dotenv for loading the token from a .env file. Before running anything you need a GitHub Personal Access Token, created at https://github.com/settings/tokens, with the read:user scope, and stored either in a .env file or exported in your shell:
touch .env
echo "GH_TOKEN=your_token_here" >> .envThen the first run is one argument, the username whose contributions you want to animate:
gh-space-shooter torvaldsWhat you should see is an animated file written to disk named after the username, and a statistics summary in the console. The output can be a .gif or a .webp, and the README gives the shorter forms as well, so gh-space-shooter torvalds -o my-game.webp writes a WebP instead. The frame rate is adjustable with --fps, where a lower value gives a smaller file, and --max-frame stops the animation early.
Strategy, frames and saving raw data to dodge rate limits
Three flags shape the output. The strategy flag sets the attack pattern, with column, row and random available, and random as the default. The fps flag controls animation frame rate, 40 being the default and 25 giving a smaller file at the cost of smoothness. The max-frame flag cuts the animation at a given frame count, which is the quickest way to keep a file size down. Separately, the tool can save the raw contribution data as JSON with --raw-output and read it back with --raw-input, which the README describes as a way to save API rate limits when you want to render several variants from one fetch:
gh-space-shooter --raw-input data.json --output game.webpThe saved JSON is the same structure the API returns, with a username, a total_contributions count and a list of weeks holding days, each day carrying a date, a count and a level. The level is the value that maps to contribution density in the standard graph, which is what lets the renderer scale enemy size. Saving the raw payload is also the escape hatch for testing a different strategy or frame rate without hitting the API again.
The v2 Action rewrites your last commit instead of adding one
The Action is where the interesting engineering decision sits. In v2, the action amends the previous commit when that commit contains only the game file and carries the same commit message, which the README frames as a way to prevent repository bloat from daily commits. Setting no-amend to true disables that, and no-commit to true skips committing and pushing entirely, leaving the generated file in the workspace so you can commit it yourself, for example to batch several runs into one commit. The commit-message input lets you control the message. This behaviour also carries a requirement: the README says fetch-depth: 2 is needed in actions/checkout@v6 for it to work, because amending needs the previous commit present in the checkout rather than a shallow clone. The workflow also asks for contents: write permission and passes the token through the github-token input, which is required, while username defaults to the repository owner if you leave it out.
Where this approach stops: tokens, permissions and what a GIF cannot say
The limits are practical. The whole flow depends on a token with read:user scope, and the Action needs a token with write access to push the regenerated image. A scheduled workflow that runs daily on your own repository is fine, but a fork or an organisation policy that restricts workflow permissions will break it. The README also notes that generating the image consumes API rate limit, which is why the raw JSON round trip exists. Beyond the mechanics, there is a design limit worth naming: an animated game communicates engagement to a human reader far less precisely than a contribution graph does. A README visitor wants to know when you were active, and a shooter animation hides that behind frames and effects. And since the token needs to exist somewhere, anyone running this on a shared machine has to think about where that .env file lives.
Release pace, packaging and the MIT licence
Maintenance is visible in the release history. The last push was on 2026-10-10, and the recent versions are v2.0.5 on 2026-08-12, v2.0.4 on 2026-07-05 and v2.0.3 on 2026-06-22, which is a steady run of patch level work on the 2.0 line rather than big feature jumps. The package version in pyproject.toml matches the current release, and bumpversion is configured in that file with tag set to false, so version bumps are made in the working tree. Packaging uses hatchling as the build backend, with pytest configured against the tests directory and pythonpath set to src, so the source layout is src/ plus tests/. The repository also carries a uv.lock and a .python-version file. The licence is MIT, which is the simplest case for a dependency you intend to run in a scheduled workflow, and the tool also carries a CLAUDE.md file with contributor guidance.
Editorial conclusion
gh-space-shooter fits a developer who wants a daily animated image in a profile README and is comfortable giving a workflow the contents: write permission and a token. Skip it for a profile that needs a static, accessible summary of activity, since an animated GIF of a game conveys less than a graph does, and skip it if you cannot expose a token with read:user scope. Before adopting, run gh-space-shooter torvalds once locally with GH_TOKEN set to check the animation quality, then read action.yml for the inputs the workflow exposes, and decide whether the amend behaviour in v2 suits how you want your history to look.
Frequently asked questions
How do I install gh-space-shooter and generate my first GIF?
Install it with pip install gh-space-shooter on Python 3.12 or newer, set a GitHub Personal Access Token with the read:user scope in a .env file as GH_TOKEN, then run gh-space-shooter torvalds. The animation is written as a .gif or, with the -o option, a .webp.
Can gh-space-shooter run automatically every day in my repository?
Yes, through its GitHub Action, which the README shows scheduled with a daily cron and a workflow_dispatch manual trigger. You add the workflow to .github/workflows/update-game.yml, give it contents: write permission and a github-token, and set an output-path such as game.gif.
Why does the workflow need fetch-depth: 2 in actions/checkout@v6?
The README says this is needed for the v2 amend behaviour to work. Because the action amends the previous commit when it holds only the game file with the same commit message, the previous commit has to be present in the checkout rather than a shallow clone. Setting no-amend to true disables the behaviour.
How can I avoid hitting the GitHub API rate limit when rendering?
Save the contribution payload with --raw-output data.json and then render from that file with --raw-input data.json, which the README describes as saving API rate limits. The saved JSON holds the username, total_contributions and weeks of days with date, count and level.
Is there a way to use gh-space-shooter without installing anything?
Yes. The README points to a web interface at gh-space-shooter.kiyo-n-zane.com for on-demand GIF generation with nothing installed locally.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/czl9707-gh-space-shooter)Was this useful?