CS-GO-Stats-Analysis Turns Demo Files Into a Theory of Awareness
A Python pipeline that syncs kills to game state, measures crosshair geometry, and clusters players into roles without relying on gut feel.
- This repo treats awareness as a stat, which makes a CS:GO kill feel like forensic evidence instead of a scoreboard event.
- Its most interesting move is to sync a kill to the preceding frame and measure the angle between the victim’s view and the attacker’s position.
- The analysis layer matters because it adds economy context, SteamID normalization, and over 70 tracked metrics around the same core event.
- K-Means role discovery gives the project a second opinion on players, one that comes from behavior instead of labels or ego.
The stat CS:GO players actually feel
Most stat pages can tell you who got the kill. This repo asks the sharper question: who was already lost before the duel began? That is why the most useful metric here is not K/D, but Angle From Killer, a way to quantify how surprised a player was when danger arrived.
That shift matters because tactical shooters are full of invisible advantages. Good crosshair placement, late information, and bad timing all show up as a death in the final log. The repo’s premise is that the real story lives one frame earlier.
This repository contains the code for a CS:GO performance analysis.
How a demo becomes a question about perception
The pipeline starts with a .dem file and ends with per-player metrics. In between, the code parses frames, matches kill events to the immediately preceding game state, and turns spatial relationships into numbers.
That is the key technical trick. The function the research points to, matchKillToFrame, is doing more than bookkeeping. It is anchoring a human event to a machine-readable moment so the stat can measure context, not just outcome.
# Conceptual shape of the analysis
kill_frame = matchKillToFrame(demo_frames, kill_event)
victim = kill_frame['victim']
attacker = kill_frame['attacker']
aafk = angle_between(victim['crosshair'], attacker['position'])
player_stats[player_id]['afk'].append(aafk)