Turn any GitHub contribution graph into a living 3D city. Every day is a building, height is commit volume, and the whole year lights up as a skyline you can orbit.
GitHub's own Skyline was the fun way to look back at a year of work, and it is gone. skyline.github.com no longer resolves. gitcity is a replacement that runs entirely in the browser, needs no login, and does more than the original: five themes, per-day inspection, PNG export, and the STL export that made Skyline worth printing.
- Any profile, any year. Type a username, pick a year or the rolling last twelve months.
- Reads exactly like your graph. Colour follows GitHub's own 0 to 4 intensity levels, so the city and the contribution graph always agree.
- Log scaled heights. One 100 commit day does not flatten the rest of the year into the pavement.
- Hover any building to see the date and exact count.
- Leaderboard. Rank up to twelve people by contribution volume across all time, the rolling last twelve months, or any single year. Click a row to build that person's city.
- Head-to-head. Drop two people into one scene on one shared scale and read the gap off the skyline.
- Five themes. Neon, Aurora, Sunset, Matrix, Ice.
- Save a PNG of the current camera angle.
- Export an STL and print your year. Buildings sit on a base plate, ready to slice.
- Time-lapse replay. Play the period back in calendar order and watch the city grow day by day, or skip it with a click.
- Shareable links.
?user=torvalds&range=2024&theme=sunsetrestores the exact view,?users=a,b,c&period=allrestores a board, and?vs=a,brestores a head-to-head.
- Seven themes — Neon, Aurora, Sunset, Matrix, Ice, Magma, and Cyberpunk, with theme choice persisted locally.
- Two camera modes — orbit with a perspective lens or switch to an orthographic projection for a clean, technical view.
- Auto-rotate and full-screen toggles for hands-free presentations.
- Exports — PNG (opaque or transparent), printable STL, binary glTF, and CSV for the leaderboard and head-to-head comparisons.
- Stats and sharing — copy stats to the clipboard, copy a deep link, and view keyboard shortcuts with
?. - Recent searches — quickly reload previously viewed profiles from a dropdown.
- Keyboard navigation —
/jumps to the search box andEsccloses any open panel, alongside the rest of the shortcuts below.
Put a group side by side and rank them by contribution volume, across all time, the rolling last twelve months, or any single year. Click a row to build that person's city.
Your board is remembered locally and travels in the URL, so a link carries the whole comparison.
Two people, one scene, one scale. Both years are rendered as neighbouring districts and a table breaks the year down into five numbers with the winner of each highlighted.
The shared scale is the whole point. Heights and colours are bucketed against the busiest day found across both accounts, not each account's own maximum, so a quiet year genuinely looks quiet next to a loud one. Read against GitHub's per profile intensity levels the two skylines would look identical no matter how far apart the totals were.
On a phone the pair is turned a quarter so the year runs down the long axis and the two cities sit left and right instead of one behind the other.
| Aurora | Sunset |
|---|---|
![]() |
![]() |
| Matrix | Ice |
|---|---|
![]() |
![]() |
While the search box is not focused:
/— jump to the search boxR— load a random profileT— replay the period as a time-lapse0— reset the cameraP— download PNGL— download STLS— copy share link?— show or hide the shortcut listEsc— close any open panel
The whole city is a single InstancedMesh, one instance per day, so a full year is one draw call.
MeshStandardMaterial has no per-instance emissive slot, which is a problem when every building needs to glow its own colour. gitcity patches the shader in onBeforeCompile and drives totalEmissiveRadiance from the instance colour instead. The same patch adds the window grid, generated procedurally from world position and surface normal, so rows line up across a building regardless of how tall it scaled and every wall gets covered without a texture.
The reflection is a second InstancedMesh sharing the same matrices with scale.y = -1, sitting under a semi-transparent plaza. Cheaper than a real reflection pass and it survives bloom, which a Reflector does not.
Camera framing projects all eight corners of the city's bounding box into camera space and solves for the distance that keeps every corner inside the frustum. That is what keeps the full year in frame on both an ultrawide monitor and a portrait phone.
The leaderboard costs exactly one request per person no matter how many periods you compare. The all time payload carries a per year total map alongside the day array, so switching between all time, the last twelve months, and individual years is a local re-sort with no network traffic.
Contribution data comes from github-contributions-api, a public, read-only mirror of the profile graph. No token, no login, nothing stored. If the API is unreachable the app falls back to a generated demo city so the scene is never empty.
npm install
npm run devThen open http://localhost:5173.
npm run build # type check + production bundle
npm run smoke # end-to-end checks against a running dev server
npm run smoke:resilience # failure paths, with the API stubbed outThe smoke test covers data loading, hover raycasting, theme switching, STL and PNG export, the time-lapse replay, the leaderboard and its CSV export, head-to-head comparison, keyboard navigation, unknown user handling, deep links, and the mobile layout. A separate resilience suite checks retry and error handling against a failing API.
The resilience test covers what happens when things go wrong: a request that fails once and succeeds on retry, an API that never answers, a username that does not exist, and Compare being clicked while another city is still building.
Issues and pull requests are welcome. Good first additions: new themes in src/themes.ts (self contained, just a colour ramp and a couple of numbers), a glTF exporter alongside the STL one, or an orthographic camera mode.
MIT






