Gamer's Grimoire
A dashboard for my indie game club: playtime, achievement progress and a shared backlog, pulled live from the Steam Web API.
- ROLE
- Solo project — design and build
- TIMELINE
- Jul — Aug 2026
- STATUS
- LIVE
- TYPE
- WEB APP · DASHBOARD
- STACK
- NEXT.JS
- REACT
- TYPESCRIPT
- TAILWIND
- STEAM API
- IGDB
- VERCEL
Open the live site (gamers-grimoire.vercel.app)- BUILD TIME
- 1 WK
- APIS — STEAM + IGDB
- 2
- DATABASES
- 0
- PAGES
- 3
The problem
Our club plays one game at a time, and who'd played what, how far everyone had got and what to play next all lived in a group chat. I wanted one page that answered those questions automatically, with nobody needing to log in or update anything.
The approach
No database, no login
The whole site runs off one config file — members, picks and nominations — plus live Steam data, so keeping it current is a one-line edit.
Two APIs, one view
Steam supplies playtime, achievements, ownership and Australian store pricing; IGDB adds time-to-beat estimates through Twitch OAuth with automatic token refresh, matched by title.
Tiered caching
Next.js revalidation at 10 minutes for player stats, 24 hours for store data and 7 days for IGDB keeps the dashboard current while staying inside API rate limits.
Architecture
All fetching happens on the server. Each source is cached for as long as its data can change, two server modules join and sort the results, and the three pages render from them. There is no database; the config file is the only thing edited by hand.
- club.ts to club-stats.ts
- Steam Web API to Player stats
- Steam Web API to Store data
- IGDB API to Time-to-beat
- Player stats to club-stats.ts
- Player stats to backlog.ts
- Store data to backlog.ts
- Time-to-beat to backlog.ts
- club-stats.ts to / (dashboard)
- club-stats.ts to /history
- backlog.ts to /backlog
What it does
Dashboard
The current pick front and centre: each member's achievement progress, a race to finish, the rarest unlock in the club, and a terminal-style status panel that sums it all up.
Achievement gallery and the BADlog
Every achievement for every member, unlocked or still locked — plus the BADlog, which shows what everyone has been playing instead over the last two weeks.
Backlog
Games everyone already owns come first, then nominations with how many members own each one and live Australian sale prices — on-sale games sorted to the top.
Works on a phone
The same dashboard, fully responsive, so it gets checked from the couch as often as from a desk.
Tech stack
- React 19UI
- Tailwind CSS 4Styling
- Next.js 16App Router, RSC
- Fetch cacheRevalidation
- TypeScriptLanguage
- Steam Web APIPrimary source
- IGDB APITime-to-beat
- club.tsConfig
- VercelHosting, CI
- GitHubSource control
- React 19
- Component model fits the repeated member tables, tabs and galleries.
- Tailwind CSS 4
- Utility classes made the dark-fantasy theme quick to iterate on.
- Next.js 16
- Server components do all fetching, so API keys never reach the browser.
- Fetch cache
- Per-source cache lifetimes with no extra infrastructure to run.
- TypeScript
- Typed Steam and IGDB responses surface shape changes at build time.
- Steam Web API
- The source of truth for playtime, achievements, ownership and prices.
- IGDB API
- Licensed HowLongToBeat data, via Twitch OAuth with automatic token refresh.
- club.ts
- A typed file instead of a database: the data only changes once per pick.
- Vercel
- Free tier, and every push to the main branch deploys automatically.
- GitHub
- Version history, and pushes trigger the Vercel build.
The outcome
Deployed on Vercel and used by the club for each pick. It also became the design testbed for this portfolio — the tilt cards, CRT effects and command palette started here.