Each image and animation on this page visualizes how players from both teams can move across a map from the start of the round, and where they are able to see each other for the first time.
Every frame represents a specific moment in time. At that moment, the visualization shows which parts of the map each team could theoretically have reached if they moved optimally from spawn and which areas can first see each other at this point in time.
The animated GIF at the top shows this process continuously over time, while the individual images below allow you to inspect specific moments in more detail.
I recently came back to CS after a long break, and due to changes to existing maps and the addition of new ones, I had no idea about the timings anymore. None of my friends play the game, so I couldn't hop into a server with someone to check where the Ts and CTs meet at the start of the round.
I also didn't want to do this manually after every map update. So I decided to write a small program that calculates these meeting points automatically.
The main tool for this is Awpy, a Python library for CS2 demo parsing and analysis. It also provides functionality for navigation and visibility by reading the game files.
The maps are subdivided into a rectangular grid: typically 200x200 tiles, or 100x100 for more horizontal and square maps. From this grid, a graph is built representing which tiles are connected based on walkability and jumpability.
Once the graph is built, the program calculates the shortest path to each tile from all CT and T spawn points separately, along with their distances. Then, step by step, it considers all tiles reachable after X time or at effective distance X.
For each newly reached tile, it checks which tiles reachable by the other team are visible. This identifies potential first-contact locations.
Maps have 10,000-40,000 tiles, making it impossible to visualize each individually. To reduce clutter, an approximation is used: only groups of tiles that have not been previously spotted are plotted. This logic ensures images show meaningful steps without overwhelming detail.
To achieve this, tiles are first clustered into small spatial groups (the black rectangles). The grouping is based on the 2D grid used for pathfinding: neighbouring tiles in x/y are merged into blocks (roughly corresponding to 5x5-10x10 tiles in world space, depending on map granularity). Within each block, tiles are further split by height so that a single group never mixes levels that are more than one jump apart or stack multiple floors at the same x/y position. The result is that each group behaves like one "patch of ground" a player could stand on.
During the spread simulation, each team tracks two states per group:
CT and T tiles are then processed together, always taking the next closest tile to any spawn. For each newly reached tile, the algorithm:
A new image (spread frame) is only saved when this logic reveals something new: either a previously unseen group is spotted for the first time, or a fixed distance/time interval since the last frame has passed. Combined with grouping, this keeps the number of frames per map to roughly 200-300 while still capturing the key moments where new areas of the map become visible and relevant for first contact.
The website is automatically kept up-to-date via a nightly job that checks for CS2 updates, identifies changed maps, and regenerates the calculations and images for those maps.
CS2's standard navigation meshes are triangle-based and optimized for bots. Using their centroids for pathfinding produces suboptimal paths that can drastically distort timings, especially in tight areas like D2 Long. Additionally, these meshes are incomplete: some fast routes (e.g., Mirage A Default → Balcony) do not exist in the bot mesh, so shortest paths are missed.
Here is a visualization comparing paths from T spawn to the top of Con on Mirage:
Standard mesh path
200x200 grid mesh path
You can see the standard mesh path is significantly longer, irregular, and misses shortcuts such as the jump between Tetris and stairs. This motivated the creation of the 200x200 grid approach used in this project.
Full original mirage mesh with connections for reference: