Counter-Strike 2

Counter-Strike 2

32 ratings
How to fully make use of the CS2 Annotation API
By Nydauron
This guide covers the newly added annotation/map guide system Valve added to CS2. It goes over the basic console commands that Valve has implemented for basic needs as well as documentation for properties within the annotation config file.
2
   
Award
Favorite
Favorited
Unfavorite
DISCLAIMER
I am not responsible if you ♥♥♥♥ up your config. ALWAYS BACK UP YOUR CONFIG OR YOUR ANNOTATIONS BEFORE MAKING ANY CHANGES!!

Please also note that since this feature is still in the early stages of its life, the behavior of some of the commands in this guide may be subject to change. While it is unlikely that breaking changes will occur due to how lightweight the annotations API is, If you follow this guide and a later CS2 version breaks your buy binds, please note it down in the comments, and I will try to get the guide updated as soon as possible.
Migrating Old Annotations
If you have old annotations saved to your disk prior to the Nov 27, 2024 update, you must move the txt files to a new directory:

Old File Path
New File Path
<your Steam directory>\steamapps\common\Counter-Strike Global Offensive\game\csgo\annotations\<filename>.txt
<your Steam directory>\steamapps\common\Counter-Strike Global Offensive\game\csgo\annotations\local\<filename>\<filename>.txt
What are annotations?
Annotations are a new system Valve has implemented into CS2. These are also referred to as "map guides" and can used to provide but are not limited to tips, timings, and grenade throws for the player to learn for a given map.

Valve has achieved this level of versatility by creating a lightweight API that facilitates the creation, manipulation, and customizability of annotations that can fit most mapmakers' and players' needs.
How to create a basic annotation
Annotations are composed of one or more nodes. While most are simply one node, grenade annotations, by default, use three, and you can customize them to use more if need be (more on that later).

First, ensure the convar `sv_allow_annotations` is set to true:
sv_allow_annotations 1

There can be a maximum of 300 nodes loaded at once. Prior to the Nov 27, 2024 update, only 100 nodes could have been loaded at once.

[ ANNOTATIONS ]
...
- Increased node limit from 100 to 300

For basic construction, the devs have provided us plebians with a couple of commands:
> find annotation_ [Console] name value default flags help text [Console] _______________________________ ______ ________ _______ ___________________________________________________________________ [Console] annotation_append client Load annotation to a file without clearing existing annotations [Console] annotation_auto_load false client [Console] annotation_clear client Clear all annotation [Console] annotation_create client Creates an annotation [Console] annotation_delete_previous_node_set client Delete the last node set created [Console] annotation_load client Load annotation to a file after first clearing existing annotations [Console] annotation_reload client Reload the annotation file [Console] annotation_reload_language_file client Creates an annotation [Console] annotation_save client Save annotation to a file

Of the ones to get started, you really need to know only:
annotation_create <type> annotation_clear annotation_delete_previous_node_set annotation_load <filename> annotation_reload annotation_save <filename>

so we will only go over these commands below.

annotation_create
There are currently five different types of nodes you can create

grenade: annotation_create grenade [smoke|flash|he|molotov|incendiary|decoy] "label" position: annotation_create position "label" text: annotation_create text "title" "text" float|surface [faceplayer] line: annotation_create line float|surface [new] spot: annotation_create spot

annotation_create grenade
A simple grenade annotation. The command will automatically create three nodes based on:
- Your current position and facing direction
- The endpoint of the last grenade trajectory you threw


Prior to the Nov 27, 2024 update, the grenade trajectory only has full interactive support for smokes, but the update brought with it full support for all five nade types. The Dec 18, 2024 update silently patched the command to allow for the creation of molotov and incendiary lineups.

[ ANNOTATIONS ]
...
- Added support for grenade types other than Smoke

Now, you can pass in the type of grenade throw into the command (one of "smoke", "flash", "he", "molotov", "incendiary", or "decoy") to create specific lineups for each type of grenade.


annotation_create position
Places a node at the player's feet and direction. This can be useful for, say, documenting spawns.


anntation_create text
Creates a text-based node. The node has two sections that display text: a title and a description.
- The title appears on the top and by default, has a larger font.
- The description appears directly below the title that has a smaller font by default.

Text nodes can be mounted to surfaces that the player is looking at or be floating a couple of units away from the player. Additionally, they can be configured to always face the player.

annotation_create line
This command doesn't directly create annotation lines but instead creates points where lines can be drawn to.

Line point nodes can be mounted to a surface that the player is looking at or floating (the player's current position).

To create a line, you must first run:
annotation_create line <surface|float> new
where `<surface|float>` is one of the config options as mentioned above on where the point will be mounted to.
The `new` parameter specifies that you are creating a new line and the previous point node you created will not connect to the newly created point node.

To now draw a line, run:
annotation_create line <surface|float>
and you should see the newly created line.

The line can be connected to more points by repeating the top command.

annotation_create spot
Creates an aim spot node. These are typically used for grenade annotations but can be used for other tips.

The command creates the node based on the player's current:
- position
- facing direction

The node itself will appear a reddish color when you are not in the correct position and will fade to a greenish color as you closely approach the position where the spot node was generated from.

A niche use case for these types of nodes besides grenades would be for wallbang spots.

annotation_delete_previous_node_set and annotation_clear
Both of these commands achieve similar behaviors:
- `annotation_delete_previous_node_set` deletes the last batch created nodes created from one command
- `annotation_clear` clears all nodes from memory

Prior to the Nov 27, 2024 update, `annotation_delete_previous_node_set` was named `annotation_delete_previous_node`, and there was a bug with `annotation_delete_previous_node` where the annotation render ends up getting zombified after deletion (only remediation is to reload the map).
[ ANNOTATIONS ]
...
- Fixed annotation_delete_previous_node not cleaning up particle effects

annotation_load
Loads up a file based on the passed name.
annotation_load <filename>
It will assume the file extension is .txt and will automatically append ".txt" to the end of the file name you provide.

If you are curious where to import annotations that you got from online, place them in "<your Steam directory>\steamapps\common\Counter-Strike Global Offensive\game\csgo\annotations\local\<filename>\" and name it "<filename>.txt" where "<filename>" is the name of the file and leaf folder.

annotation_reload
Reloads the current file by re-reading it. Note that the annotations stored in memory will get wiped.

annotation_save
One of the most important commands; it tells the game where to save your created annotations! This is because your annotations do not get auto-saved and you must save them manually in order for it to persist across your map or game sessions.
annotation_save <filename>
The annotations will be stored in a txt file located in "<your Steam directory>\steamapps\common\Counter-Strike Global Offensive\game\csgo\annotations\local\<filename>\".

You can then go into the file and manually edit or add nodes.
Annotation Configuration Settings (for advanced configuration)
If you want to go beyond what the console commands can do, then you will need to edit the annotation key-value configuration file directly. I would recommend you using something like VSCode or VSCodium that offers on-demand file updating, but editors like Notepad++ will work just fine.

The configuration settings are stored in a kv3 encoded format, which has many parallels to JSON but offers more features, such as multiline strings, binary encodings, versioning, and comments.

If you want to get a good understanding of how the annotation configuration file works, I suggest you read the docs below and play around with the config in game.
Configuration Setting Documentation
Common settings
Settings that can be used for all nodes

Enabled
bool

Whether the node is enabled
The option seems to only visually affect text
This includes line, position, and spot node text
  • If enabled, text will be visible if the player is in range
  • If disabled, the text will not be visible from anywhere

Type
string

The type of node

Possible values:
  • grenade
  • text
  • position
  • line

Id
string UUID

A version 4 UUID. Other nodes most typically reference this value to specify a parent node through the "MasterNodeId" field.

SubType
string

If a type (text, position) does not have any subtypes, it is set to "main".

Grenade types have three different subtypes:
  • "main" - the primary node and is the standing position
  • "aim_target" - a node for the aiming spot and text
  • "destination" - the destination target

Line types have two different subtypes:
  • "main" - the starting point node
  • "aim_target" - any of the connecting point nodes

Position
array[float]

The x, y, and z coordinates in units where the node is located in the map
This is used when checking how far a player is from the location

Angles
array[float]

x coord rotates along the y-axis
y coord rotates along the z-axis
z coord rotates along the x-axis

VisiblePfx
bool

Whether the annotation is visible to the player

Color
array[uint, uint, uint]

Array representing the corresponding RGB value
Color values range from 0 to 255

TextPositionOffset
array[float, float, float]

The number of units to move the text relative to "Position." This is useful if you want to move the text to a readable area or if you want the text to be visible in a different position from where the player's position is.

TextFacePlayer
bool

Whether the text should face the player at all times

RevealOnSuccess
bool

  • Node is displayed only when guides are off
  • Once StreakLimitGuidesOn amount of successes occur, then the node will be displayed
    • If set to true, ensure that the node has a MasterNodeId that is pointing to a grenade type node

Title
obj

Refer to "The Text and Desc Object" section.

Desc
obj

Refer to "The Text and Desc Object" section.

MasterNodeId
optional: string UUID

Specifies the parent node
Typically used in:
  • grenade annotations
    • The subtypes link back to the main parent node
    • Since Dec 18, 2024, when multiple grenade groupings are loaded at once and you stand on a particular grenade annotation, the game will hide the rest of the grenade
  • lines
    • Each parent node is the start of the line, and every other node links to the node that comes directly before it (like a chain or linked list)
    • The parent (main subtype) node is the start of the line, and points to a child (aim_target subtype) (like a chain or linked list)
    • If and only if the MasterNodeId links to a line node will it draw a line between them
    • Since Dec 18, 2024, the leaf node (node without a MasterNodeId linking to another line node) can be used to link towards other nodes (e.g. grenade main subtype node to allow for hiding when not in use).

Grenade-specific node properties
These properties only need to be present in the "main" subtype of the "grenade" type nodes
StreakLimitGuidesOn
uint

The number of consecutive successes the player must make with the guides on

StreakLimitGuidesOff
uint

The number of consecutive successes the player must make without the guides

JumpThrow
bool

Whether the grenade throw is a jump throw
This will then force the grenade camera to display the jump throw preview.

GrenadeType
string
Since Nov 27, 2024 update

The type of grenade used for the lineup

Possible values:
  • smoke (default, if the GrenadeType property is not provided)
  • flash
  • he
  • fire (This is considered obsolete. Was listed as an option in the `Dec 09 15:59:58` build. Please use either "molotov" or "incendiary" instead.)
  • molotov
  • incendiary (Since Dec 18, 2024)
  • decoy

The Text and Desc Object
The "Title" and "Desc" properties both use an object with identical property names:

Text
string

The text that is displayed to the user
If this text is not desired, it can be set to the empty string (i.e., "") and the game will not render the text bubble.

FontSize
uint

The size of the text

FadeInDist and FadeOutDist

There are some commonalities and some behavior quirks with this setting, hence why it is grouped as such.

FadeInDist
float

The distance for when to fade in the text

FadeOutDist
float

The distance for when to fade out the text.
This is specifically used to specify the fade out distance as the player gets closer to the text.

FadeInDist and FadeOutDist Special Values
  • Set this to -1 to prevent any fade out or fade in as the user gets close.
    • -1 for FadeInDist will keep the text at maximum opacity regardless of how far away the player is
    • -1 for FadeOutDist will keep the text at maximum opacity regardless of how close the player is
  • If FadeInDist is a lower value than FadeOutDist, it can result in some "undefined behavior"
    • It appears that the text does not fade in, but rather, as it approaches FadeOutDist, it suddenly appears (typically around 50 units away from FadeOutDist), then fades as it gets close to FadeOutDist. From this point, the text does not fade in as you get closer.
  • Note: negative floats will work. As you approach a distance of 0 to the text, the text will start to fade but will reach a low but non-zero opacity. If you want the desired fade out distance to be -1, use surrounding values (i.e. -0.9999 or -1.0001) to achieve the fade out as -1.0 seems to be the magic number for disabling fade out.

ShowBackground
bool
Since Nov 27, 2024 update

Disables the darkened background for the text
Publishing your map guide to the workshop
The Easy Way
With the Dec 18, 2024 update, Valve has added the ability for you to publish your map guides to the workshop. You can publish them by running the command:
workshop_annotation_submit

A popup should then appear to then allow you to add a name to the submission and the txt file of the annotations. Once you hit submit, this will create a basic submission, and Steam overlay will navigate to the page of the newly created workshop item. You can edit the submission further using the workshop page.
Updating an existing map guide on the workshop
If you have an existing map guide on the workshop that you would like to update, as of the January 21, 2025 update, you can use:
workshop_annotation_submit <submission ID>

to update one of your existing annotation submissions on the workshop. After the first update, the ID is saved to the annotation file, so `workshop_annotation_submit` will simply update the appropriate annotation submission that is currently loaded into memory.

The Advanced Way
While this process is a little bit more complicated, uploading workshop content using SteamCMD allows you to edit the thumbnail, add changelogs after an update, and more.

Install SteamCMD
In general, to update an existing workshop item, we need to use SteamCMD. Download and extract/install the program.

Structure of the workshop item
We will also need to structure the payload that will be uploaded to the workshop. Create a new folder for your workshop item. Inside that you will have three things:
My workshop item/ |-- content/ |-- image.png |-- metadata.vdf
  • The `content/` folder represents the content that will be uploaded to the workshop. When a user subscribes to your workshop, these are the files they will download. This is where your annotation txt file should be copied into.
  • `image.png` is a generic name and can be named anything, but it represents the preview image of the workshop item. When exporting annotations using `annotation_save`, a PNG file of the map and utility is generated, which is used as the preview image when you run `workshop_annotation_submit`. This field is optional but highly recommended, and you can choose to use the PNG file the game generates or your own custom PNG or JPG.
  • `metadata.vdf` is a required file that contains the metadata of the workshop submission. Read the section below for more info on each of the fields.

metadata.vdf Properties
  • "appid" The App ID of the game you are uploading for (CS2 is ID 730)
  • "publishedfileid" The ID of the workshop submission. The ID can be found at the end of the workshop item URL in the URL parameter "id" (e.g. the workshop id of the URL steamcommunity(dot)com/sharedfiles/filedetails/?id=3387027106 is "3387027106"). Set this to "0" if you want to create a new submission instead if updating an existing one.
  • "contentfolder" The absolute path of where the content folder is located.
  • "previewfile" The absolute path of the image that will be used as the preview image for the workshop item
  • "visibility" "0" = Public, "1" = Only friends, "2" = Private/Contributors Only
  • "title" The title of the workshop item
  • "description" An escaped multiline string representing the description of the workshop item. BBCode can be used here if so desired. Since the string is escaped, escape sequences (e.g., "\n", "\t", "\\") will be printed verbatim. If you want multiple lines, the string can be multiline inside the configuration file.
  • "changenote" An escaped multiline string representing new changenotes to the workshop submission. Only applicable if "publishedfileid" is not "0".

Running SteamCMD and Uploading to the Workshop
WARNING: It is recommended to first log out of/close the Steam client first before logging into Steam via StemCMD. There have been some "unwanted interactions" if both clients are logged into the same account on the same computer.

Load up a cmd prompt in the current directory where SteamCmd is installed. On Windows, you can then run the following command to publish your changes to the workshop:
steamcmd.exe +login USERNAME +workshop_build_item "<absolute path to the metadata.vdf file>" +quit
On Linux or MacOS, the command would be:
./steamcmd.sh +login USERNAME +workshop_build_item "<absolute path to the metadata.vdf file>" +quit
In either case, enter your password and complete the 2FA prompt. Check for errors printed to the terminal, and if all goes well, your workshop entry will be updated.

If you run the command shortly into the future, your login credentials should be cached, and the password and 2FA prompts should not appear.
Conclusion
Overall, I think this feature is quite amazing and is quite versatile in use cases. I am glad that the devs are iterating on this API, having expanded it to include all types of nades. That being said, I hope this was a comprehensive guide on how to build map guides for either yourself, your friends, or your team.

Phew, that was long! Thanks for reading through this guide! As always, I appreciate your constructive feedback, whether you found it useful, encountered any issues, or have any other comments.
18 Comments
slumz 15 Oct @ 2:26am 
is there a way to load a .cfg inside the workshop folder ?
FgZ | LeNoune 27 Sep @ 8:48am 
Hello.
As anyone find a way to play annotations on a dedicated server with other people ?
76561199467038902 13 Sep @ 11:42am 
Hi. Where can I find the official Annotation file for Train made by Valve?
4ngu5 1 Feb @ 6:38pm 
thanks for the reply but I figured out the answer to my own question eventually lmao.
for what I was trying to do using "annotation_create position" combined with "annotation_create spot" works fine to create a standing point with multiple lineups shown from that location without needing to create each individually.
Nydauron  [author] 30 Jan @ 6:11pm 
@4ngu5 : The grenade nodes will need all 3 node subtypes to function properly, but you can add spot nodes to the main node by using the "MasterNodeId" field to each of the main spot nodes. Each main spot node would have the main grenade node's id as the value assigned to "MasterNodeId".
4ngu5 30 Jan @ 7:37am 
Old thread sorry but is there a way I could change 3 sets of annotations (main, aim_target, and destination) to use one position and three spot annotations instead? Every time I try to change it manually it stops working.
alxo 4 Jan @ 3:29am 
Now we just need to have filter on every map in the map pool in the workshop, so we can actually see people posting these
Hello, Is guidemap can use in online?like "map de_dust2" with firends.I try it,but only can use in local, once more than one player in room, the "annotation load"conmmand is failue,even I submit in workshop
Nydauron  [author] 15 Dec, 2024 @ 12:12pm 
@MegaSnake9 : Huh weird. Yeah, I cannot recreate the sprite in the screenshot. Tried it again, and this time, I get a scrolling frame of all the different sprites, and when I resave the nodes, the property it gets set to is "right".

Tried it on mirage as well at the lamp flash position like you did, and it also had the same behavior as above.

When I restarted my game, went back into mirage, and repeated the above, I instead got the top half of the HE sprite. GrenadeType still gets set to "right" when the annotations are dumped to a file.

I'm assuming this is simply undefined behavior for which the devs have not created a deterministic fallback case. This would explain why our results are inconsistent between sessions.
MegaSnake9 15 Dec, 2024 @ 7:09am 
Regarding GrenadeType, I shared a screen shot on my profile