Why I scored every game on Steam for bang-for-your-buck
The story of the number, including the two times I had it backwards.
I grew up doing math before I bought a game.
The PC was a hand-me-down and the budget was real. Twenty dollars was a decision, so before I spent it I ran the numbers in my head: how many hours would I actually get, how good was it really, was it worth the money. I built my first PC in middle school partly so I could stop guessing at that math. I got good at it.
Steam BANGERS is that math, for every game on Steam, as one number. It's called the BANG Score: 0 to 100, how much real game you get per dollar. A 41 is a 41. You can argue about it. People do.
This is the story of how I built it, including the two times I had the math backwards and the one time I deleted the entire catalog and the build said it went fine.
Find the unowned question
The first thing I did was look at who owns what.
SteamDB owns the raw data. SteamCharts owns concurrent players. HowLongToBeat owns playtime. OpenCritic and Metacritic own the review scores. Every obvious lane already has a sharp, trusted, citable site sitting in it.
Nobody owns the question I actually ask before I buy: is this worth the money. That's the whole product. Not another review aggregator, not another playtime database. One opinionated number for value, on the one question with no incumbent.
A value score is arguable by design. That's a feature here. The argument is the point.
The data killed my first idea on day one
My plan was simple and wrong. Price divided by hours played equals value. Cheaper per hour, better deal. I'd pull median playtime per game from SteamSpy and divide.
I spiked it before building anything, which is the one habit that has never let me down. SteamSpy's median-playtime field came back as 0. For every game. Steam's 2018 privacy changes broke the sampling that fed it, and the field has been dead ever since. My load-bearing input did not exist.
The aggregate that survived Steam's privacy lockdown is global achievement completion percent: of everyone who owns a game, what fraction unlocked the achievements. It's noisy and it needs careful handling, but it's a real signal of whether people actually get into a game or bounce off it. So the "what do you get" axis stopped being how long people play and became how far they get. The data picked the metric, not me.
The math feels right and is wrong
Here's the second time I had it backwards, and it took a rebuild to see it.
Dollars per hour feels like value. A $20 game that's 40 hours is "$0.50 an hour," a steal. A $20 game that's 4 hours is "$5 an hour," a ripoff. Sort by that and you have your score.
Except dollars per hour optimizes for length. It pays developers to pad. A four-hour game that's perfect ends up below an eighty-hour grind nobody finishes, because the grind has more hours to divide into. Every short masterpiece on Steam scored like a rip-off. The number was punishing exactly the games I'd most want it to find.
The fix was to flip what leads. Reviews set the ceiling. The shrunk review score is the base of the number, and price-per-hour only moves you down within that ceiling, never up past it. Reviews lead, length follows. I added a per-genre length floor too, so a short-by-design narrative game gets measured against other narrative games instead of against a CRPG. After the change, the short masterpieces rose and the padded grinds fell, which is the entire job. The hardest bug in the formula was never the math. It was that the wrong axis felt like the right one.
Show the number, never the recipe
The formula is secret. I show the score and every input fact behind it. I never show the weights.
This is deliberate, and it's the Metacritic move: own the number, not the method. A published formula gets gamed within a week and is boring the whole time. A secret score that people argue about ("why is Hades a 36?") is the engagement engine. Trust doesn't come from publishing the weights. It comes from a methodology page that shows every input, the data sources, and the honest places the score is weak. The controversy should come from rigor, not from hiding the math.
The pipeline, which is the actual point
The raw crawl data lives on an Apache Iceberg table on Cloudflare R2. Not raw JSON blobs in a bucket. An open catalog, with schema and snapshots and time-travel, queryable straight from DuckDB or Spark without moving the data anywhere.
That's overkill for a side project, and that's on purpose. It's the same open-lakehouse shape I run in production at work: raw data on an Iceberg catalog, a deterministic transform, served fast at the edge. From that raw layer, a scheduled job re-scores everything several times a day and publishes to an edge database replica, so a page load never waits on the pipeline. The whole thing is deterministic and AI-free. A score is a function of the data, full stop.
The build said it went fine
The scariest data-loss bug I shipped exited zero and printed that the publish was ok.
The first real production rebuild shrank the catalog from 1,491 games to 15. The compute image I run the rebuild in didn't include the file with the full game list, so the loader fell back to a 15-game development seed, scored those 15, and published them straight over the live data. There was no crash. Fifteen rows is a perfectly successful build of the wrong input. It is the worst kind of bug, because every signal you'd normally trust says it worked.
I caught it in the run output, added the missing file to the image, and re-ran. The raw layer still had all 1,491 games, so the catalog came back intact. The lesson stuck though: the guard for "did the build work" is not a try/except. A try/except catches crashes, and this didn't crash. The guard is verifying the row count. Now I check that the rebuilt catalog isn't suspiciously smaller than the last one before anything publishes.
The number exists now
I still run the hours-per-dollar math before I buy a game. The difference is that now there's a number for it, rebuilt from fresh data several times a day across roughly 95,000 games, and I get to argue with it.
Every game on Steam, scored for value, is on this site. The recipe stays mine.