Skip to content
← Back to Projects
game-feed screenshot or preview

game-feed

Publish Your Gaming History as a Site and a JSON Feed

2026Tools

A GitHub template that turns your Steam and RetroAchievements history into a site you can browse and a static JSON feed anything else can read. A scheduled Action collects, commits, and deploys — there is no server, no database, and no API key to hand out. Fork it, add your own secrets, and it starts publishing the next morning.

game-feed collects what you have been playing from Steam and RetroAchievements, keeps its own copy of the cover art and achievement badges, and publishes the lot as a browsable site and a static JSON feed. Everything runs on GitHub: a scheduled Action collects, commits the result, and deploys to Pages. Because the data is committed rather than fetched at runtime, the site has no backend to keep alive and the feed has no rate limit to respect.

It is published as a repository template rather than an app. You press "Use this template", add secrets for whichever sources you want — each is independent, so Steam only, RetroAchievements only, or both — and the first collection runs on demand. One file at the repo root, site.config.ts, is the only thing you are expected to edit; both the collector and the front end import it, so there is no second place for the two halves to disagree.

Four routes make up the site. Colors come from semantic tokens with no dark: variants anywhere in the markup, so light and dark are the same components reading a different set of values — which is why each shot below is really two, following whichever theme your system is set to.

Overview — stat tiles, playtime and platform charts, and recent activity
Library — filter and sort state lives in the address bar, so any view is a link
Game detail — cover art, completion, and the most recent unlocks
Data — the feed documented against wherever it is deployed

Key Features

  • Two sources, one shape — Steam and RetroAchievements normalize into a single record, so the same components render either
  • A /data route that documents the feed against wherever it is deployed, with the URLs already filled in
  • Filterable library with search, platform, source, and sort state kept in the address bar, so any view is a link
  • An append-only art library: images are never re-downloaded and never overwritten, so a published URL always returns the same bytes
  • Separate collect and display config — omit a field from the feed entirely, or keep collecting it and just hide it here
  • Dated history snapshots, written only on the days the data actually changed
  • Sample data on a fresh fork, so the site renders like a real one before you have collected anything

The feed is the part I care most about. The site is a front end over a file it also publishes, so anything on screen is available to another app: GitHub Pages serves data/games.json with Access-Control-Allow-Origin: *, and one fetch gets the whole library as an array. Image fields are absolute URLs onto the same deployment, so a consumer can render a cover with no rewriting. This site is the proof: the Playing page reads a feed of exactly this shape and renders it, with no code shared between the two projects beyond the type declaration.

The type declaration is the contract between the two halves: src/types/index.ts has no imports, so it can be copied into a consuming project verbatim, and the collector imports the same file — which means the published shape cannot drift from the declared one. The README documents every upstream API and its version, separating the versioned Steam endpoints from the unversioned ones that can change without warning.

Running on GitHub

  • collect.yml — daily at 07:23 UTC or on demand: collect, commit and tag if anything changed, then build and deploy
  • deploy.yml — build and deploy on any push to main that is not the collector's own data commit
  • ci.yml — prettier, ESLint, tsc, and a production build on every push and pull request
  • Both deploy jobs derive the base path from the repository name, so a project page and a user page both work unedited
  • The template guards its own collection job, so it does not post a failing run every morning with no library to collect

The front end was scaffolded from react-ts-starter, my own React and TypeScript starting point, which is where the semantic color tokens, the accessibility baseline, the lazy-loaded route shell, and the prettier → lint → typecheck → build gate come from. game-feed is what that scaffold looks like with a real data problem attached to it.